diff --git a/interface/resources/qml/Stats.qml b/interface/resources/qml/Stats.qml index 2c991aa9dd..23aa256cdc 100644 --- a/interface/resources/qml/Stats.qml +++ b/interface/resources/qml/Stats.qml @@ -340,10 +340,10 @@ Item { text: "GPU: " + root.gpuFrameTime.toFixed(1) + " ms" } StatText { - text: "GPU (Per pixel): " + root.gpuFrameTimePerPixel.toFixed(5) + " ns/pp" + text: "GPU (Per pixel): " + root.gpuFrameTimePerPixel.toFixed(1) + " ns/pp" } StatText { - text: "GPU frame size: " + root.gpuFrameSize.x + " x " + root.gpuFrameSize.y + text: "GPU frame size: " + root.gpuFrameSize.x.toFixed(0) + " x " + root.gpuFrameSize.y.toFixed(0) } StatText { text: "LOD Target: " + root.lodTargetFramerate + " Hz Angle: " + root.lodAngle + " deg" diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index b50ad8f595..eba8664f72 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3742,18 +3742,6 @@ void Application::resizeGL() { DependencyManager::get()->setFrameBufferSize(fromGlm(renderSize)); } - auto renderResolutionScale = getRenderResolutionScale(); - if (displayPlugin->getRenderResolutionScale() != renderResolutionScale) { - auto renderConfig = _graphicsEngine.getRenderEngine()->getConfiguration(); - assert(renderConfig); - auto mainView = renderConfig->getConfig("RenderMainView.RenderDeferredTask"); - // mainView can be null if we're rendering in forward mode - if (mainView) { - mainView->setProperty("resolutionScale", renderResolutionScale); - } - displayPlugin->setRenderResolutionScale(renderResolutionScale); - } - // FIXME the aspect ratio for stereo displays is incorrect based on this. float aspectRatio = displayPlugin->getRecommendedAspectRatio(); _myCamera.setProjection(glm::perspective(glm::radians(_fieldOfView.get()), aspectRatio, @@ -8547,23 +8535,7 @@ void Application::shareSnapshot(const QString& path, const QUrl& href) { } float Application::getRenderResolutionScale() const { - auto menu = Menu::getInstance(); - if (!menu) { - return 1.0f; - } - if (menu->isOptionChecked(MenuOption::RenderResolutionOne)) { - return 1.0f; - } else if (menu->isOptionChecked(MenuOption::RenderResolutionTwoThird)) { - return 0.666f; - } else if (menu->isOptionChecked(MenuOption::RenderResolutionHalf)) { - return 0.5f; - } else if (menu->isOptionChecked(MenuOption::RenderResolutionThird)) { - return 0.333f; - } else if (menu->isOptionChecked(MenuOption::RenderResolutionQuarter)) { - return 0.25f; - } else { - return 1.0f; - } + return RenderScriptingInterface::getInstance()->getViewportResolutionScale(); } void Application::notifyPacketVersionMismatch() { diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index bb087c96d5..8bee8de8c3 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -382,28 +382,6 @@ Menu::Menu() { // Developer > Render > OpenVR threaded submit addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::OpenVrThreadedSubmit, 0, true); - // Developer > Render > Resolution - MenuWrapper* resolutionMenu = renderOptionsMenu->addMenu(MenuOption::RenderResolution); - QActionGroup* resolutionGroup = new QActionGroup(resolutionMenu); - resolutionGroup->setExclusive(true); - -#if defined(Q_OS_MAC) - resolutionGroup->addAction(addCheckableActionToQMenuAndActionHash(resolutionMenu, MenuOption::RenderResolutionOne, 0, false)); -#else - resolutionGroup->addAction(addCheckableActionToQMenuAndActionHash(resolutionMenu, MenuOption::RenderResolutionOne, 0, true)); -#endif - - resolutionGroup->addAction(addCheckableActionToQMenuAndActionHash(resolutionMenu, MenuOption::RenderResolutionTwoThird, 0, false)); - - #if defined(Q_OS_MAC) - resolutionGroup->addAction(addCheckableActionToQMenuAndActionHash(resolutionMenu, MenuOption::RenderResolutionHalf, 0, true)); -#else - resolutionGroup->addAction(addCheckableActionToQMenuAndActionHash(resolutionMenu, MenuOption::RenderResolutionHalf, 0, false)); -#endif - - resolutionGroup->addAction(addCheckableActionToQMenuAndActionHash(resolutionMenu, MenuOption::RenderResolutionThird, 0, false)); - resolutionGroup->addAction(addCheckableActionToQMenuAndActionHash(resolutionMenu, MenuOption::RenderResolutionQuarter, 0, false)); - //const QString = "Automatic Texture Memory"; //const QString = "64 MB"; //const QString = "256 MB"; diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 7c462e4e74..70687786a9 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -168,12 +168,6 @@ namespace MenuOption { const QString RenderMaxTexture4096MB = "4096 MB"; const QString RenderMaxTexture6144MB = "6144 MB"; const QString RenderMaxTexture8192MB = "8192 MB"; - const QString RenderResolution = "Scale Resolution"; - const QString RenderResolutionOne = "1"; - const QString RenderResolutionTwoThird = "2/3"; - const QString RenderResolutionHalf = "1/2"; - const QString RenderResolutionThird = "1/3"; - const QString RenderResolutionQuarter = "1/4"; const QString RenderSensorToWorldMatrix = "Show SensorToWorld Matrix"; const QString RenderIKTargets = "Show IK Targets"; const QString RenderIKConstraints = "Show IK Constraints"; diff --git a/interface/src/scripting/RenderScriptingInterface.cpp b/interface/src/scripting/RenderScriptingInterface.cpp index 608f1d30e9..338a5ab883 100644 --- a/interface/src/scripting/RenderScriptingInterface.cpp +++ b/interface/src/scripting/RenderScriptingInterface.cpp @@ -30,14 +30,16 @@ void RenderScriptingInterface::loadSettings() { _shadowsEnabled = (_shadowsEnabledSetting.get()); _ambientOcclusionEnabled = (_ambientOcclusionEnabledSetting.get()); _antialiasingEnabled = (_antialiasingEnabledSetting.get()); + _viewportResolutionScale = (_viewportResolutionScaleSetting.get()); }); forceRenderMethod((RenderMethod)_renderMethod); forceShadowsEnabled(_shadowsEnabled); forceAmbientOcclusionEnabled(_ambientOcclusionEnabled); forceAntialiasingEnabled(_antialiasingEnabled); + forceViewportResolutionScale(_viewportResolutionScale); } -RenderScriptingInterface::RenderMethod RenderScriptingInterface::getRenderMethod() { +RenderScriptingInterface::RenderMethod RenderScriptingInterface::getRenderMethod() const { return (RenderMethod) _renderMethod; } @@ -64,7 +66,7 @@ QStringList RenderScriptingInterface::getRenderMethodNames() const { return refrenderMethodNames; } -bool RenderScriptingInterface::getShadowsEnabled() { +bool RenderScriptingInterface::getShadowsEnabled() const { return _shadowsEnabled; } @@ -88,7 +90,7 @@ void RenderScriptingInterface::forceShadowsEnabled(bool enabled) { }); } -bool RenderScriptingInterface::getAmbientOcclusionEnabled() { +bool RenderScriptingInterface::getAmbientOcclusionEnabled() const { return _ambientOcclusionEnabled; } @@ -112,7 +114,7 @@ void RenderScriptingInterface::forceAmbientOcclusionEnabled(bool enabled) { }); } -bool RenderScriptingInterface::getAntialiasingEnabled() { +bool RenderScriptingInterface::getAntialiasingEnabled() const { return _antialiasingEnabled; } @@ -145,3 +147,37 @@ void RenderScriptingInterface::forceAntialiasingEnabled(bool enabled) { } +float RenderScriptingInterface::getViewportResolutionScale() const { + return _viewportResolutionScale; +} + +void RenderScriptingInterface::setViewportResolutionScale(float scale) { + if (_viewportResolutionScale != scale) { + forceViewportResolutionScale(scale); + emit settingsChanged(); + } +} + +void RenderScriptingInterface::forceViewportResolutionScale(float scale) { + // just not negative values or zero + if (scale <= 0.f) { + return; + } + _renderSettingLock.withWriteLock([&] { + _viewportResolutionScale = (scale); + _viewportResolutionScaleSetting.set(scale); + + auto renderConfig = qApp->getRenderEngine()->getConfiguration(); + assert(renderConfig); + auto deferredView = renderConfig->getConfig("RenderMainView.RenderDeferredTask"); + // mainView can be null if we're rendering in forward mode + if (deferredView) { + deferredView->setProperty("resolutionScale", _viewportResolutionScale); + } + auto forwardView = renderConfig->getConfig("RenderMainView.RenderForwardTask"); + // mainView can be null if we're rendering in forward mode + if (forwardView) { + forwardView->setProperty("resolutionScale", _viewportResolutionScale); + } + }); +} diff --git a/interface/src/scripting/RenderScriptingInterface.h b/interface/src/scripting/RenderScriptingInterface.h index 39a88d4aad..9b96448c9d 100644 --- a/interface/src/scripting/RenderScriptingInterface.h +++ b/interface/src/scripting/RenderScriptingInterface.h @@ -29,6 +29,7 @@ class RenderScriptingInterface : public QObject { Q_PROPERTY(bool shadowsEnabled READ getShadowsEnabled WRITE setShadowsEnabled NOTIFY settingsChanged) Q_PROPERTY(bool ambientOcclusionEnabled READ getAmbientOcclusionEnabled WRITE setAmbientOcclusionEnabled NOTIFY settingsChanged) Q_PROPERTY(bool antialiasingEnabled READ getAntialiasingEnabled WRITE setAntialiasingEnabled NOTIFY settingsChanged) + Q_PROPERTY(float viewportResolutionScale READ getViewportResolutionScale WRITE setViewportResolutionScale NOTIFY settingsChanged) public: RenderScriptingInterface(); @@ -66,7 +67,7 @@ public slots: * @function Render.getRenderMethod * @returns {number} "DEFERRED" or "FORWARD" */ - RenderMethod getRenderMethod(); + RenderMethod getRenderMethod() const; /**jsdoc * Sets the current render method @@ -88,7 +89,7 @@ public slots: * @function Render.getShadowsEnabled * @returns {bool} true if shadows are enabled, otherwise false */ - bool getShadowsEnabled(); + bool getShadowsEnabled() const; /**jsdoc * Enables or disables shadows @@ -102,7 +103,7 @@ public slots: * @function Render.getAmbientOcclusionEnabled * @returns {bool} true if ambient occlusion is enabled, otherwise false */ - bool getAmbientOcclusionEnabled(); + bool getAmbientOcclusionEnabled() const; /**jsdoc * Enables or disables ambient occlusion @@ -116,7 +117,7 @@ public slots: * @function Render.getAntialiasingEnabled * @returns {bool} true if anti-aliasing is enabled, otherwise false */ - bool getAntialiasingEnabled(); + bool getAntialiasingEnabled() const; /**jsdoc * Enables or disables anti-aliasing @@ -130,14 +131,14 @@ public slots: * @function Render.getViewportResolutionScale * @returns {number} */ - // float getViewportResolutionScale(); + float getViewportResolutionScale() const; /**jsdoc * Sets the current viewport resolution scale * @function Render.setViewportResolutionScale * @param {number} resolutionScale - between epsilon and 1.0 */ - // void setViewportResolutionScale(float resolutionScale); + void setViewportResolutionScale(float resolutionScale); signals: void settingsChanged(); @@ -150,19 +151,22 @@ private: int _renderMethod{ RENDER_FORWARD ? render::Args::RenderMethod::FORWARD : render::Args::RenderMethod::DEFERRED }; bool _shadowsEnabled{ true }; bool _ambientOcclusionEnabled{ false }; - bool _antialiasingEnabled { true }; + bool _antialiasingEnabled{ true }; + float _viewportResolutionScale{ 1.0f }; // Actual settings saved on disk Setting::Handle _renderMethodSetting { "renderMethod", RENDER_FORWARD ? render::Args::RenderMethod::FORWARD : render::Args::RenderMethod::DEFERRED }; Setting::Handle _shadowsEnabledSetting { "shadowsEnabled", true }; Setting::Handle _ambientOcclusionEnabledSetting { "ambientOcclusionEnabled", false }; Setting::Handle _antialiasingEnabledSetting { "antialiasingEnabled", true }; + Setting::Handle _viewportResolutionScaleSetting { "viewportResolutionScale", 1.0f }; // Force assign both setting AND runtime value to the parameter value void forceRenderMethod(RenderMethod renderMethod); void forceShadowsEnabled(bool enabled); void forceAmbientOcclusionEnabled(bool enabled); void forceAntialiasingEnabled(bool enabled); + void forceViewportResolutionScale(float scale); static std::once_flag registry_flag; }; diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp index e0505770f5..ce70e91128 100644 --- a/interface/src/ui/PreferencesDialog.cpp +++ b/interface/src/ui/PreferencesDialog.cpp @@ -14,10 +14,9 @@ #include #include #include -#include #include #include - +#include "scripting/RenderScriptingInterface.h" #include "Application.h" #include "DialogsManager.h" #include "LODManager.h" @@ -103,6 +102,22 @@ void setupPreferences() { preference->setItems(refreshRateProfiles); preferences->addPreference(preference); } + { + // Expose the Viewport Resolution Scale + auto getter = []()->float { + return RenderScriptingInterface::getInstance()->getViewportResolutionScale(); + }; + + auto setter = [](float value) { + RenderScriptingInterface::getInstance()->setViewportResolutionScale(value); + }; + + auto scaleSlider = new SliderPreference(GRAPHICS_QUALITY, "Resolution Scale", getter, setter); + scaleSlider->setMin(0.25f); + scaleSlider->setMax(1.0f); + scaleSlider->setStep(0.02f); + preferences->addPreference(scaleSlider); + } // UI static const QString UI_CATEGORY { "User Interface" }; diff --git a/interface/src/ui/Stats.cpp b/interface/src/ui/Stats.cpp index dc9780adf5..8b9b9743f0 100644 --- a/interface/src/ui/Stats.cpp +++ b/interface/src/ui/Stats.cpp @@ -377,7 +377,7 @@ void Stats::updateStats(bool force) { auto displayPlugin = qApp->getActiveDisplayPlugin(); if (displayPlugin) { QVector2D dims(displayPlugin->getRecommendedRenderSize().x, displayPlugin->getRecommendedRenderSize().y); - dims *= displayPlugin->getRenderResolutionScale(); + dims *= qApp->getRenderResolutionScale(); STAT_UPDATE(gpuFrameSize, dims); STAT_UPDATE(gpuFrameTimePerPixel, (float)(gpuContext->getFrameTimerGPUAverage()*1000000.0 / double(dims.x()*dims.y()))); } diff --git a/libraries/plugins/src/plugins/DisplayPlugin.h b/libraries/plugins/src/plugins/DisplayPlugin.h index 1cad9b1e11..ca4e3bc392 100644 --- a/libraries/plugins/src/plugins/DisplayPlugin.h +++ b/libraries/plugins/src/plugins/DisplayPlugin.h @@ -147,14 +147,6 @@ public: virtual void submitFrame(const gpu::FramePointer& newFrame) = 0; virtual void captureFrame(const std::string& outputName) const { } - virtual float getRenderResolutionScale() const { - return _renderResolutionScale; - } - - void setRenderResolutionScale(float renderResolutionScale) { - _renderResolutionScale = renderResolutionScale; - } - // The size of the rendering target (may be larger than the device size due to distortion) virtual glm::uvec2 getRecommendedRenderSize() const = 0; @@ -235,8 +227,6 @@ protected: MovingAverage _movingAveragePresent; - float _renderResolutionScale { 1.0f }; - private: QMutex _presentMutex; QWaitCondition _presentCondition; diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index 51729fc5cf..3ab9340906 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -273,44 +273,6 @@ graphics::MeshPointer DeferredLightingEffect::getSpotLightMesh() { return _spotLightMesh; } -gpu::FramebufferPointer PreparePrimaryFramebuffer::createFramebuffer(const char* name, const glm::uvec2& frameSize) { - gpu::FramebufferPointer framebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create(name)); - auto colorFormat = gpu::Element::COLOR_SRGBA_32; - - auto defaultSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR); - auto primaryColorTexture = gpu::Texture::createRenderBuffer(colorFormat, frameSize.x, frameSize.y, gpu::Texture::SINGLE_MIP, defaultSampler); - - framebuffer->setRenderBuffer(0, primaryColorTexture); - - auto depthFormat = gpu::Element(gpu::SCALAR, gpu::UINT32, gpu::DEPTH_STENCIL); // Depth24_Stencil8 texel format - auto primaryDepthTexture = gpu::Texture::createRenderBuffer(depthFormat, frameSize.x, frameSize.y, gpu::Texture::SINGLE_MIP, defaultSampler); - - framebuffer->setDepthStencilBuffer(primaryDepthTexture, depthFormat); - - return framebuffer; -} - -void PreparePrimaryFramebuffer::configure(const Config& config) { - _resolutionScale = config.resolutionScale; -} - -void PreparePrimaryFramebuffer::run(const RenderContextPointer& renderContext, Output& primaryFramebuffer) { - glm::uvec2 frameSize(renderContext->args->_viewport.z, renderContext->args->_viewport.w); - glm::uvec2 scaledFrameSize(glm::vec2(frameSize) * _resolutionScale); - - // Resizing framebuffers instead of re-building them seems to cause issues with threaded - // rendering - if (!_primaryFramebuffer || _primaryFramebuffer->getSize() != scaledFrameSize) { - _primaryFramebuffer = createFramebuffer("deferredPrimary", scaledFrameSize); - } - - primaryFramebuffer = _primaryFramebuffer; - - // Set viewport for the rest of the scaled passes - renderContext->args->_viewport.z = scaledFrameSize.x; - renderContext->args->_viewport.w = scaledFrameSize.y; -} - void PrepareDeferred::run(const RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs) { auto args = renderContext->args; diff --git a/libraries/render-utils/src/DeferredLightingEffect.h b/libraries/render-utils/src/DeferredLightingEffect.h index 84b3127443..4779376410 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.h +++ b/libraries/render-utils/src/DeferredLightingEffect.h @@ -74,36 +74,6 @@ private: friend class RenderDeferredCleanup; }; -class PreparePrimaryFramebufferConfig : public render::Job::Config { - Q_OBJECT - Q_PROPERTY(float resolutionScale MEMBER resolutionScale NOTIFY dirty) -public: - - float resolutionScale{ 1.0f }; - -signals: - void dirty(); -}; - -class PreparePrimaryFramebuffer { -public: - - using Output = gpu::FramebufferPointer; - using Config = PreparePrimaryFramebufferConfig; - using JobModel = render::Job::ModelO; - - PreparePrimaryFramebuffer(float resolutionScale = 1.0f) : _resolutionScale{resolutionScale} {} - void configure(const Config& config); - void run(const render::RenderContextPointer& renderContext, Output& primaryFramebuffer); - - gpu::FramebufferPointer _primaryFramebuffer; - float _resolutionScale{ 1.0f }; - -private: - - static gpu::FramebufferPointer createFramebuffer(const char* name, const glm::uvec2& size); -}; - class PrepareDeferred { public: // Inputs: primaryFramebuffer and lightingModel diff --git a/libraries/render-utils/src/RenderCommonTask.cpp b/libraries/render-utils/src/RenderCommonTask.cpp index ae53539770..e5de6ccd27 100644 --- a/libraries/render-utils/src/RenderCommonTask.cpp +++ b/libraries/render-utils/src/RenderCommonTask.cpp @@ -106,34 +106,6 @@ void DrawLayered3D::run(const RenderContextPointer& renderContext, const Inputs& } } -void CompositeHUD::run(const RenderContextPointer& renderContext, const gpu::FramebufferPointer& inputs) { - assert(renderContext->args); - assert(renderContext->args->_context); - - // We do not want to render HUD elements in secondary camera - if (nsightActive() || renderContext->args->_renderMode == RenderArgs::RenderMode::SECONDARY_CAMERA_RENDER_MODE) { - return; - } - - // Grab the HUD texture -#if !defined(DISABLE_QML) - gpu::doInBatch("CompositeHUD", renderContext->args->_context, [&](gpu::Batch& batch) { - glm::mat4 projMat; - Transform viewMat; - renderContext->args->getViewFrustum().evalProjectionMatrix(projMat); - renderContext->args->getViewFrustum().evalViewTransform(viewMat); - batch.setProjectionTransform(projMat); - batch.setViewTransform(viewMat, true); - if (inputs) { - batch.setFramebuffer(inputs); - } - if (renderContext->args->_hudOperator) { - renderContext->args->_hudOperator(batch, renderContext->args->_hudTexture, renderContext->args->_renderMode == RenderArgs::RenderMode::MIRROR_RENDER_MODE); - } - }); -#endif -} - void Blit::run(const RenderContextPointer& renderContext, const gpu::FramebufferPointer& srcFramebuffer) { assert(renderContext->args); assert(renderContext->args->_context); @@ -205,6 +177,34 @@ void Blit::run(const RenderContextPointer& renderContext, const gpu::Framebuffer }); } +void NewOrDefaultFramebuffer::run(const render::RenderContextPointer& renderContext, const Input& input, Output& output) { + RenderArgs* args = renderContext->args; + // auto frameSize = input; + glm::uvec2 frameSize(args->_viewport.z, args->_viewport.w); + output.reset(); + + // First if the default Framebuffer is the correct size then use it + auto destBlitFbo = args->_blitFramebuffer; + if (destBlitFbo && destBlitFbo->getSize() == frameSize) { + output = destBlitFbo; + return; + } + + // Else use the lodal Framebuffer + if (_outputFramebuffer && _outputFramebuffer->getSize() != frameSize) { + _outputFramebuffer.reset(); + } + + if (!_outputFramebuffer) { + _outputFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("newFramebuffer.out")); + auto colorFormat = gpu::Element::COLOR_SRGBA_32; + auto defaultSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR); + auto colorTexture = gpu::Texture::createRenderBuffer(colorFormat, frameSize.x, frameSize.y, gpu::Texture::SINGLE_MIP, defaultSampler); + _outputFramebuffer->setRenderBuffer(0, colorTexture); + } + + output = _outputFramebuffer; +} void ResolveFramebuffer::run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs) { RenderArgs* args = renderContext->args; @@ -235,42 +235,6 @@ void ResolveFramebuffer::run(const render::RenderContextPointer& renderContext, }); } -void ResolveNewFramebuffer::run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs) { - RenderArgs* args = renderContext->args; - auto srcFbo = inputs; - outputs.reset(); - - // Check valid src - if (!srcFbo) { - return; - } - - // Check valid size for sr and dest - auto frameSize(srcFbo->getSize()); - - // Resizing framebuffers instead of re-building them seems to cause issues with threaded rendering - if (_outputFramebuffer && _outputFramebuffer->getSize() != frameSize) { - _outputFramebuffer.reset(); - } - - if (!_outputFramebuffer) { - _outputFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("resolvedNew.out")); - auto colorFormat = gpu::Element::COLOR_SRGBA_32; - auto defaultSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR); - auto colorTexture = gpu::Texture::createRenderBuffer(colorFormat, frameSize.x, frameSize.y, gpu::Texture::SINGLE_MIP, defaultSampler); - _outputFramebuffer->setRenderBuffer(0, colorTexture); - } - - gpu::Vec4i rectSrc; - rectSrc.z = frameSize.x; - rectSrc.w = frameSize.y; - gpu::doInBatch("ResolveNew", args->_context, [&](gpu::Batch& batch) { batch.blit(srcFbo, rectSrc, _outputFramebuffer, rectSrc); }); - - outputs = _outputFramebuffer; -} - - - void ExtractFrustums::run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& output) { assert(renderContext->args); assert(renderContext->args->_context); diff --git a/libraries/render-utils/src/RenderCommonTask.h b/libraries/render-utils/src/RenderCommonTask.h index 4f72600d34..756445a30f 100644 --- a/libraries/render-utils/src/RenderCommonTask.h +++ b/libraries/render-utils/src/RenderCommonTask.h @@ -13,6 +13,8 @@ #include "LightStage.h" #include "LightingModel.h" + + class BeginGPURangeTimer { public: using JobModel = render::Job::ModelO; @@ -75,16 +77,6 @@ protected: bool _opaquePass { true }; }; -class CompositeHUD { -public: - // IF specified the input Framebuffer is actively set by the batch of this job before calling the HUDOperator. - // If not, the current Framebuffer is left unchanged. - //using Inputs = gpu::FramebufferPointer; - using JobModel = render::Job::ModelI; - - void run(const render::RenderContextPointer& renderContext, const gpu::FramebufferPointer& inputs); -}; - class Blit { public: using JobModel = render::Job::ModelI; @@ -92,6 +84,16 @@ public: void run(const render::RenderContextPointer& renderContext, const gpu::FramebufferPointer& srcFramebuffer); }; +class NewOrDefaultFramebuffer { +public: + using Input = glm::uvec2; + using Output = gpu::FramebufferPointer; + using JobModel = render::Job::ModelIO; + + void run(const render::RenderContextPointer& renderContext, const Input& input, Output& output); +private: + gpu::FramebufferPointer _outputFramebuffer; +}; class ResolveFramebuffer { public: @@ -102,18 +104,6 @@ public: void run(const render::RenderContextPointer& renderContext, const Inputs& source, Outputs& dest); }; -class ResolveNewFramebuffer { -public: - using Inputs = gpu::FramebufferPointer; - using Outputs = gpu::FramebufferPointer; - using JobModel = render::Job::ModelIO; - - void run(const render::RenderContextPointer& renderContext, const Inputs& source, Outputs& dest); -private: - gpu::FramebufferPointer _outputFramebuffer; -}; - - class ExtractFrustums { public: diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 624869bbf5..e513fb7282 100644 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -47,6 +47,7 @@ #include "FadeEffect.h" #include "BloomStage.h" #include "RenderUtilsLogging.h" +#include "RenderHUDLayerTask.h" #include "AmbientOcclusionEffect.h" #include "AntialiasingEffect.h" @@ -96,11 +97,8 @@ RenderDeferredTask::RenderDeferredTask() void RenderDeferredTask::configure(const Config& config) { // Propagate resolution scale to sub jobs who need it auto preparePrimaryBufferConfig = config.getConfig("PreparePrimaryBuffer"); - auto upsamplePrimaryBufferConfig = config.getConfig("PrimaryBufferUpscale"); assert(preparePrimaryBufferConfig); - assert(upsamplePrimaryBufferConfig); - preparePrimaryBufferConfig->setProperty("resolutionScale", config.resolutionScale); - upsamplePrimaryBufferConfig->setProperty("factor", 1.0f / config.resolutionScale); + preparePrimaryBufferConfig->setResolutionScale(config.resolutionScale); } void RenderDeferredTask::build(JobModel& task, const render::Varying& input, render::Varying& output) { @@ -232,8 +230,6 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren task.addJob("DrawInFrontOpaque", inFrontOpaquesInputs, true); task.addJob("DrawInFrontTransparent", inFrontTransparentsInputs, false); - const auto toneAndPostRangeTimer = task.addJob("BeginToneAndPostRangeTimer", "PostToneLayeredAntialiasing"); - // AA job before bloom to limit flickering const auto antialiasingInputs = Antialiasing::Inputs(deferredFrameTransform, lightingFramebuffer, linearDepthTarget, velocityBuffer).asVarying(); task.addJob("Antialiasing", antialiasingInputs); @@ -243,8 +239,8 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren task.addJob("Bloom", bloomInputs); // Lighting Buffer ready for tone mapping - const auto toneMappingInputs = ToneMappingDeferred::Inputs(lightingFramebuffer, scaledPrimaryFramebuffer).asVarying(); - task.addJob("ToneMapping", toneMappingInputs); + const auto toneMappingInputs = ToneMappingDeferred::Input(lightingFramebuffer, scaledPrimaryFramebuffer).asVarying(); + const auto toneMappedBuffer = task.addJob("ToneMapping", toneMappingInputs); // Debugging task is happening in the "over" layer after tone mapping and just before HUD { // Debug the bounds of the rendered items, still look at the zbuffer @@ -255,21 +251,11 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren } // Upscale to finale resolution - const auto primaryFramebuffer = task.addJob("PrimaryBufferUpscale", scaledPrimaryFramebuffer); + const auto primaryFramebuffer = task.addJob("PrimaryBufferUpscale", toneMappedBuffer); - // Composite the HUD and HUD overlays - task.addJob("HUD", primaryFramebuffer); - - const auto nullJitter = Varying(glm::vec2(0.0f, 0.0f)); - const auto hudOpaquesInputs = DrawLayered3D::Inputs(hudOpaque, lightingModel, nullJitter).asVarying(); - const auto hudTransparentsInputs = DrawLayered3D::Inputs(hudTransparent, lightingModel, nullJitter).asVarying(); - task.addJob("DrawHUDOpaque", hudOpaquesInputs, true); - task.addJob("DrawHUDTransparent", hudTransparentsInputs, false); - - task.addJob("ToneAndPostRangeTimer", toneAndPostRangeTimer); - - // Blit! - task.addJob("Blit", primaryFramebuffer); + // HUD Layer + const auto renderHUDLayerInputs = RenderHUDLayerTask::Input(primaryFramebuffer, lightingModel, hudOpaque, hudTransparent).asVarying(); + task.addJob("RenderHUDLayer", renderHUDLayerInputs); } RenderDeferredTaskDebug::RenderDeferredTaskDebug() { @@ -435,6 +421,44 @@ void RenderDeferredTaskDebug::build(JobModel& task, const render::Varying& input } +gpu::FramebufferPointer PreparePrimaryFramebuffer::createFramebuffer(const char* name, const glm::uvec2& frameSize) { + gpu::FramebufferPointer framebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create(name)); + auto colorFormat = gpu::Element::COLOR_SRGBA_32; + + auto defaultSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR); + auto primaryColorTexture = gpu::Texture::createRenderBuffer(colorFormat, frameSize.x, frameSize.y, gpu::Texture::SINGLE_MIP, defaultSampler); + + framebuffer->setRenderBuffer(0, primaryColorTexture); + + auto depthFormat = gpu::Element(gpu::SCALAR, gpu::UINT32, gpu::DEPTH_STENCIL); // Depth24_Stencil8 texel format + auto primaryDepthTexture = gpu::Texture::createRenderBuffer(depthFormat, frameSize.x, frameSize.y, gpu::Texture::SINGLE_MIP, defaultSampler); + + framebuffer->setDepthStencilBuffer(primaryDepthTexture, depthFormat); + + return framebuffer; +} + +void PreparePrimaryFramebuffer::configure(const Config& config) { + _resolutionScale = config.getResolutionScale(); +} + +void PreparePrimaryFramebuffer::run(const RenderContextPointer& renderContext, Output& primaryFramebuffer) { + glm::uvec2 frameSize(renderContext->args->_viewport.z, renderContext->args->_viewport.w); + glm::uvec2 scaledFrameSize(glm::vec2(frameSize) * _resolutionScale); + + // Resizing framebuffers instead of re-building them seems to cause issues with threaded + // rendering + if (!_primaryFramebuffer || _primaryFramebuffer->getSize() != scaledFrameSize) { + _primaryFramebuffer = createFramebuffer("deferredPrimary", scaledFrameSize); + } + + primaryFramebuffer = _primaryFramebuffer; + + // Set viewport for the rest of the scaled passes + renderContext->args->_viewport.z = scaledFrameSize.x; + renderContext->args->_viewport.w = scaledFrameSize.y; +} + void RenderTransparentDeferred::run(const RenderContextPointer& renderContext, const Inputs& inputs) { assert(renderContext->args); diff --git a/libraries/render-utils/src/RenderDeferredTask.h b/libraries/render-utils/src/RenderDeferredTask.h index 3eb1153928..969094488e 100644 --- a/libraries/render-utils/src/RenderDeferredTask.h +++ b/libraries/render-utils/src/RenderDeferredTask.h @@ -149,4 +149,42 @@ public: private: }; + +class PreparePrimaryFramebufferConfig : public render::Job::Config { + Q_OBJECT + Q_PROPERTY(float resolutionScale WRITE setResolutionScale READ getResolutionScale) +public: + float getResolutionScale() const { return resolutionScale; } + void setResolutionScale(float scale) { + const float SCALE_RANGE_MIN = 0.1f; + const float SCALE_RANGE_MAX = 2.0f; + resolutionScale = std::max(SCALE_RANGE_MIN, std::min(SCALE_RANGE_MAX, scale)); + } + +signals: + void dirty(); + +protected: + float resolutionScale{ 1.0f }; +}; + +class PreparePrimaryFramebuffer { +public: + + using Output = gpu::FramebufferPointer; + using Config = PreparePrimaryFramebufferConfig; + using JobModel = render::Job::ModelO; + + PreparePrimaryFramebuffer(float resolutionScale = 1.0f) : _resolutionScale{ resolutionScale } {} + void configure(const Config& config); + void run(const render::RenderContextPointer& renderContext, Output& primaryFramebuffer); + + gpu::FramebufferPointer _primaryFramebuffer; + float _resolutionScale{ 1.0f }; + +private: + + static gpu::FramebufferPointer createFramebuffer(const char* name, const glm::uvec2& size); +}; + #endif // hifi_RenderDeferredTask_h diff --git a/libraries/render-utils/src/RenderForwardTask.cpp b/libraries/render-utils/src/RenderForwardTask.cpp index de55f3f4ff..d65ad18aa1 100755 --- a/libraries/render-utils/src/RenderForwardTask.cpp +++ b/libraries/render-utils/src/RenderForwardTask.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include @@ -32,6 +33,7 @@ #include "FramebufferCache.h" #include "TextureCache.h" #include "RenderCommonTask.h" +#include "RenderHUDLayerTask.h" namespace ru { using render_utils::slot::texture::Texture; @@ -47,6 +49,13 @@ using namespace render; extern void initForwardPipelines(ShapePlumber& plumber); +void RenderForwardTask::configure(const Config& config) { + // Propagate resolution scale to sub jobs who need it + auto preparePrimaryBufferConfig = config.getConfig("PreparePrimaryBuffer"); + assert(preparePrimaryBufferConfig); + preparePrimaryBufferConfig->setResolutionScale(config.resolutionScale); +} + void RenderForwardTask::build(JobModel& task, const render::Varying& input, render::Varying& output) { task.addJob("SetRenderMethodTask", render::Args::FORWARD); @@ -87,16 +96,19 @@ void RenderForwardTask::build(JobModel& task, const render::Varying& input, rend // First job, alter faded fadeEffect->build(task, opaques); - // Prepare objects shared by several jobs - const auto deferredFrameTransform = task.addJob("DeferredFrameTransform"); // GPU jobs: Start preparing the main framebuffer - const auto framebuffer = task.addJob("PrepareFramebuffer"); + const auto scaledPrimaryFramebuffer = task.addJob("PreparePrimaryBuffer"); - task.addJob("PrepareForward", lightFrame); + // Prepare deferred, generate the shared Deferred Frame Transform. Only valid with the scaled frame buffer + const auto deferredFrameTransform = task.addJob("DeferredFrameTransform"); + + // Prepare Forward Framebuffer pass + const auto prepareForwardInputs = PrepareForward::Inputs(scaledPrimaryFramebuffer, lightFrame).asVarying(); + task.addJob("PrepareForward", prepareForwardInputs); // draw a stencil mask in hidden regions of the framebuffer. - task.addJob("PrepareStencil", framebuffer); + task.addJob("PrepareStencil", scaledPrimaryFramebuffer); // Draw opaques forward const auto opaqueInputs = DrawForward::Inputs(opaques, lightingModel).asVarying(); @@ -128,94 +140,103 @@ void RenderForwardTask::build(JobModel& task, const render::Varying& input, rend task.addJob("DrawZoneStack", debugZoneInputs); } - // Just resolve the msaa - const auto resolveInputs = - ResolveFramebuffer::Inputs(framebuffer, static_cast(nullptr)).asVarying(); - const auto resolvedFramebuffer = task.addJob("Resolve", resolveInputs); - //auto resolvedFramebuffer = task.addJob("Resolve", framebuffer); - #if defined(Q_OS_ANDROID) + + // Just resolve the msaa + const auto resolveInputs = ResolveFramebuffer::Inputs(scaledPrimaryFramebuffer, static_cast(nullptr)).asVarying(); + const auto resolvedFramebuffer = task.addJob("Resolve", resolveInputs); + + const auto toneMappedBuffer = resolvedFramebuffer; #else + const auto newResolvedFramebuffer = task.addJob("MakeResolvingFramebuffer"); + + + // Just resolve the msaa + const auto resolveInputs = ResolveFramebuffer::Inputs(scaledPrimaryFramebuffer, newResolvedFramebuffer).asVarying(); + const auto resolvedFramebuffer = task.addJob("Resolve", resolveInputs); + // Lighting Buffer ready for tone mapping // Forward rendering on GLES doesn't support tonemapping to and from the same FBO, so we specify // the output FBO as null, which causes the tonemapping to target the blit framebuffer - const auto toneMappingInputs = ToneMappingDeferred::Inputs(resolvedFramebuffer, static_cast(nullptr)).asVarying(); - task.addJob("ToneMapping", toneMappingInputs); + const auto toneMappingInputs = ToneMappingDeferred::Input(resolvedFramebuffer, resolvedFramebuffer).asVarying(); + const auto toneMappedBuffer = task.addJob("ToneMapping", toneMappingInputs); + #endif - // Layered Overlays - // Composite the HUD and HUD overlays - task.addJob("HUD", resolvedFramebuffer); + // Upscale to finale resolution + const auto primaryFramebuffer = task.addJob("PrimaryBufferUpscale", toneMappedBuffer); - const auto hudOpaquesInputs = DrawLayered3D::Inputs(hudOpaque, lightingModel, nullJitter).asVarying(); - const auto hudTransparentsInputs = DrawLayered3D::Inputs(hudTransparent, lightingModel, nullJitter).asVarying(); - task.addJob("DrawHUDOpaque", hudOpaquesInputs, true); - task.addJob("DrawHUDTransparent", hudTransparentsInputs, false); - - // Disable blit because we do tonemapping and compositing directly to the blit FBO - // Blit! - // task.addJob("Blit", framebuffer); + // HUD Layer + const auto renderHUDLayerInputs = RenderHUDLayerTask::Input(primaryFramebuffer, lightingModel, hudOpaque, hudTransparent).asVarying(); + task.addJob("RenderHUDLayer", renderHUDLayerInputs); } -void PrepareFramebuffer::configure(const Config& config) { +gpu::FramebufferPointer PreparePrimaryFramebufferMSAA::createFramebuffer(const char* name, const glm::uvec2& frameSize, int numSamples) { + gpu::FramebufferPointer framebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create(name)); + + auto defaultSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR); + + auto colorFormat = gpu::Element::COLOR_SRGBA_32; + auto colorTexture = + gpu::Texture::createRenderBufferMultisample(colorFormat, frameSize.x, frameSize.y, numSamples, defaultSampler); + framebuffer->setRenderBuffer(0, colorTexture); + + auto depthFormat = gpu::Element(gpu::SCALAR, gpu::UINT32, gpu::DEPTH_STENCIL); // Depth24_Stencil8 texel format + auto depthTexture = + gpu::Texture::createRenderBufferMultisample(depthFormat, frameSize.x, frameSize.y, numSamples, defaultSampler); + framebuffer->setDepthStencilBuffer(depthTexture, depthFormat); + + return framebuffer; +} + +void PreparePrimaryFramebufferMSAA::configure(const Config& config) { + _resolutionScale = config.getResolutionScale(); _numSamples = config.getNumSamples(); } -void PrepareFramebuffer::run(const RenderContextPointer& renderContext, gpu::FramebufferPointer& framebuffer) { +void PreparePrimaryFramebufferMSAA::run(const RenderContextPointer& renderContext, gpu::FramebufferPointer& framebuffer) { glm::uvec2 frameSize(renderContext->args->_viewport.z, renderContext->args->_viewport.w); + glm::uvec2 scaledFrameSize(glm::vec2(frameSize) * _resolutionScale); // Resizing framebuffers instead of re-building them seems to cause issues with threaded rendering - if (_framebuffer && (_framebuffer->getSize() != frameSize || _framebuffer->getNumSamples() != _numSamples)) { - _framebuffer.reset(); + if (!_framebuffer || (_framebuffer->getSize() != scaledFrameSize) || (_framebuffer->getNumSamples() != _numSamples)) { + _framebuffer = createFramebuffer("forward", scaledFrameSize, _numSamples); } - if (!_framebuffer) { - _framebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("forward")); - - int numSamples = _numSamples; - - auto colorFormat = gpu::Element::COLOR_SRGBA_32; - auto defaultSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR); - auto colorTexture = - gpu::Texture::createRenderBufferMultisample(colorFormat, frameSize.x, frameSize.y, numSamples, defaultSampler); - _framebuffer->setRenderBuffer(0, colorTexture); - - auto depthFormat = gpu::Element(gpu::SCALAR, gpu::UINT32, gpu::DEPTH_STENCIL); // Depth24_Stencil8 texel format - auto depthTexture = - gpu::Texture::createRenderBufferMultisample(depthFormat, frameSize.x, frameSize.y, numSamples, defaultSampler); - _framebuffer->setDepthStencilBuffer(depthTexture, depthFormat); - } - - auto args = renderContext->args; - gpu::doInBatch("PrepareFramebuffer::run", args->_context, [&](gpu::Batch& batch) { - batch.enableStereo(false); - batch.setViewportTransform(args->_viewport); - batch.setStateScissorRect(args->_viewport); - - batch.setFramebuffer(_framebuffer); - batch.clearFramebuffer(gpu::Framebuffer::BUFFER_COLOR0 | gpu::Framebuffer::BUFFER_DEPTH | - gpu::Framebuffer::BUFFER_STENCIL, - vec4(vec3(0), 0), 1.0, 0, true); - }); - framebuffer = _framebuffer; + + // Set viewport for the rest of the scaled passes + renderContext->args->_viewport.z = scaledFrameSize.x; + renderContext->args->_viewport.w = scaledFrameSize.y; } void PrepareForward::run(const RenderContextPointer& renderContext, const Inputs& inputs) { RenderArgs* args = renderContext->args; + auto primaryFramebuffer = inputs.get0(); + auto lightStageFrame = inputs.get1(); + gpu::doInBatch("RenderForward::Draw::run", args->_context, [&](gpu::Batch& batch) { args->_batch = &batch; + batch.enableStereo(false); + batch.setViewportTransform(args->_viewport); + batch.setStateScissorRect(args->_viewport); + + batch.setFramebuffer(primaryFramebuffer); + batch.clearFramebuffer(gpu::Framebuffer::BUFFER_COLOR0 | gpu::Framebuffer::BUFFER_DEPTH | + gpu::Framebuffer::BUFFER_STENCIL, + vec4(vec3(0), 0), 1.0, 0, true); + graphics::LightPointer keySunLight; auto lightStage = args->_scene->getStage(); if (lightStage) { - keySunLight = lightStage->getCurrentKeyLight(*inputs); + keySunLight = lightStage->getCurrentKeyLight(*lightStageFrame); } graphics::LightPointer keyAmbiLight; if (lightStage) { - keyAmbiLight = lightStage->getCurrentAmbientLight(*inputs); + keyAmbiLight = lightStage->getCurrentAmbientLight(*lightStageFrame); } if (keySunLight) { diff --git a/libraries/render-utils/src/RenderForwardTask.h b/libraries/render-utils/src/RenderForwardTask.h index 40d004ddb2..baf7f66c6c 100755 --- a/libraries/render-utils/src/RenderForwardTask.h +++ b/libraries/render-utils/src/RenderForwardTask.h @@ -17,39 +17,59 @@ #include "AssembleLightingStageTask.h" #include "LightingModel.h" +class RenderForwardTaskConfig : public render::Task::Config { + Q_OBJECT + Q_PROPERTY(float resolutionScale MEMBER resolutionScale NOTIFY dirty) +public: + float resolutionScale{ 1.f }; + +signals: + void dirty(); +}; + class RenderForwardTask { public: using Input = render::VaryingSet3; - using JobModel = render::Task::ModelI; + using Config = RenderForwardTaskConfig; + using JobModel = render::Task::ModelI; RenderForwardTask() {} + void configure(const Config& config); void build(JobModel& task, const render::Varying& input, render::Varying& output); }; -class PrepareFramebufferConfig : public render::Job::Config { +class PreparePrimaryFramebufferMSAAConfig : public render::Job::Config { Q_OBJECT - Q_PROPERTY(int numSamples WRITE setNumSamples READ getNumSamples NOTIFY dirty) + Q_PROPERTY(float resolutionScale WRITE setResolutionScale READ getResolutionScale) + Q_PROPERTY(int numSamples WRITE setNumSamples READ getNumSamples) public: + float getResolutionScale() const { return resolutionScale; } + void setResolutionScale(float scale) { + const float SCALE_RANGE_MIN = 0.1f; + const float SCALE_RANGE_MAX = 2.0f; + resolutionScale = std::max(SCALE_RANGE_MIN, std::min(SCALE_RANGE_MAX, scale)); + } + int getNumSamples() const { return numSamples; } void setNumSamples(int num) { numSamples = std::max(1, std::min(32, num)); - emit dirty(); } signals: void dirty(); protected: + float resolutionScale{ 1.0f }; int numSamples{ 4 }; }; -class PrepareFramebuffer { +class PreparePrimaryFramebufferMSAA { public: - using Inputs = gpu::FramebufferPointer; - using Config = PrepareFramebufferConfig; - using JobModel = render::Job::ModelO; + using Output = gpu::FramebufferPointer; + using Config = PreparePrimaryFramebufferMSAAConfig; + using JobModel = render::Job::ModelO; void configure(const Config& config); void run(const render::RenderContextPointer& renderContext, @@ -57,12 +77,15 @@ public: private: gpu::FramebufferPointer _framebuffer; + float _resolutionScale{ 1.0f }; int _numSamples; + + static gpu::FramebufferPointer createFramebuffer(const char* name, const glm::uvec2& frameSize, int numSamples); }; class PrepareForward { public: - using Inputs = LightStage::FramePointer; + using Inputs = render::VaryingSet2 ; using JobModel = render::Job::ModelI; void run(const render::RenderContextPointer& renderContext, diff --git a/libraries/render-utils/src/RenderHUDLayerTask.cpp b/libraries/render-utils/src/RenderHUDLayerTask.cpp new file mode 100644 index 0000000000..ac7a867366 --- /dev/null +++ b/libraries/render-utils/src/RenderHUDLayerTask.cpp @@ -0,0 +1,60 @@ +// +// Created by Sam Gateau on 2019/06/14 +// Copyright 2013-2019 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 "RenderHUDLayerTask.h" + +#include +#include "RenderCommonTask.h" + +using namespace render; + +void CompositeHUD::run(const RenderContextPointer& renderContext, const gpu::FramebufferPointer& inputs) { + assert(renderContext->args); + assert(renderContext->args->_context); + + // We do not want to render HUD elements in secondary camera + if (nsightActive() || renderContext->args->_renderMode == RenderArgs::RenderMode::SECONDARY_CAMERA_RENDER_MODE) { + return; + } + + // Grab the HUD texture +#if !defined(DISABLE_QML) + gpu::doInBatch("CompositeHUD", renderContext->args->_context, [&](gpu::Batch& batch) { + glm::mat4 projMat; + Transform viewMat; + renderContext->args->getViewFrustum().evalProjectionMatrix(projMat); + renderContext->args->getViewFrustum().evalViewTransform(viewMat); + batch.setProjectionTransform(projMat); + batch.setViewTransform(viewMat, true); + if (inputs) { + batch.setFramebuffer(inputs); + } + if (renderContext->args->_hudOperator) { + renderContext->args->_hudOperator(batch, renderContext->args->_hudTexture, renderContext->args->_renderMode == RenderArgs::RenderMode::MIRROR_RENDER_MODE); + } + }); +#endif +} + +void RenderHUDLayerTask::build(JobModel& task, const render::Varying& input, render::Varying& output) { + const auto& inputs = input.get(); + + const auto& primaryFramebuffer = inputs[0]; + const auto& lightingModel = inputs[1]; + const auto& hudOpaque = inputs[2]; + const auto& hudTransparent = inputs[3]; + + // Composite the HUD and HUD overlays + task.addJob("HUD", primaryFramebuffer); + + // And HUD Layer objects + const auto nullJitter = Varying(glm::vec2(0.0f, 0.0f)); + const auto hudOpaquesInputs = DrawLayered3D::Inputs(hudOpaque, lightingModel, nullJitter).asVarying(); + const auto hudTransparentsInputs = DrawLayered3D::Inputs(hudTransparent, lightingModel, nullJitter).asVarying(); + task.addJob("DrawHUDOpaque", hudOpaquesInputs, true); + task.addJob("DrawHUDTransparent", hudTransparentsInputs, false); +} diff --git a/libraries/render-utils/src/RenderHUDLayerTask.h b/libraries/render-utils/src/RenderHUDLayerTask.h new file mode 100644 index 0000000000..78cd009636 --- /dev/null +++ b/libraries/render-utils/src/RenderHUDLayerTask.h @@ -0,0 +1,34 @@ +// +// Created by Sam Gateau on 2019/06/14 +// Copyright 2013-2019 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 +// + +#ifndef hifi_RenderHUDLayerTask_h +#define hifi_RenderHUDLayerTask_h + +#include "LightingModel.h" + + +class CompositeHUD { +public: + // IF specified the input Framebuffer is actively set by the batch of this job before calling the HUDOperator. + // If not, the current Framebuffer is left unchanged. + //using Inputs = gpu::FramebufferPointer; + using JobModel = render::Job::ModelI; + + void run(const render::RenderContextPointer& renderContext, const gpu::FramebufferPointer& inputs); +}; + +class RenderHUDLayerTask { +public: + // Framebuffer where to draw, lighting model, opaque items, transparent items + using Input = render::VaryingSet4; + using JobModel = render::Task::ModelI; + + void build(JobModel& task, const render::Varying& input, render::Varying& output); +}; + +#endif // hifi_RenderHUDLayerTask_h \ No newline at end of file diff --git a/libraries/render-utils/src/ToneMappingEffect.cpp b/libraries/render-utils/src/ToneMappingEffect.cpp index 64a2adb5d4..b7cc5d3d80 100644 --- a/libraries/render-utils/src/ToneMappingEffect.cpp +++ b/libraries/render-utils/src/ToneMappingEffect.cpp @@ -47,14 +47,13 @@ void ToneMappingEffect::setToneCurve(ToneCurve curve) { } } -void ToneMappingEffect::render(RenderArgs* args, const gpu::TexturePointer& lightingBuffer, const gpu::FramebufferPointer& requestedDestinationFramebuffer) { +void ToneMappingEffect::render(RenderArgs* args, const gpu::TexturePointer& lightingBuffer, const gpu::FramebufferPointer& destinationFramebuffer) { if (!_blitLightBuffer) { init(args); } - - auto destinationFramebuffer = requestedDestinationFramebuffer; - if (!destinationFramebuffer) { - destinationFramebuffer = args->_blitFramebuffer; + + if (!lightingBuffer || !destinationFramebuffer) { + return; } auto framebufferSize = glm::ivec2(lightingBuffer->getDimensions()); @@ -83,9 +82,15 @@ void ToneMappingDeferred::configure(const Config& config) { _toneMappingEffect.setToneCurve((ToneMappingEffect::ToneCurve)config.curve); } -void ToneMappingDeferred::run(const render::RenderContextPointer& renderContext, const Inputs& inputs) { +void ToneMappingDeferred::run(const render::RenderContextPointer& renderContext, const Input& input, Output& output) { + + auto lightingBuffer = input.get0()->getRenderBuffer(0); + auto destFbo = input.get1(); + + if (!destFbo) { + destFbo = renderContext->args->_blitFramebuffer; + } - auto lightingBuffer = inputs.get0()->getRenderBuffer(0); - auto destFbo = inputs.get1(); _toneMappingEffect.render(renderContext->args, lightingBuffer, destFbo); + output = destFbo; } diff --git a/libraries/render-utils/src/ToneMappingEffect.h b/libraries/render-utils/src/ToneMappingEffect.h index 69694b13f5..faf6e514e9 100644 --- a/libraries/render-utils/src/ToneMappingEffect.h +++ b/libraries/render-utils/src/ToneMappingEffect.h @@ -82,12 +82,13 @@ signals: class ToneMappingDeferred { public: // Inputs: lightingFramebuffer, destinationFramebuffer - using Inputs = render::VaryingSet2; + using Input = render::VaryingSet2; + using Output = gpu::FramebufferPointer; using Config = ToneMappingConfig; - using JobModel = render::Job::ModelI; + using JobModel = render::Job::ModelIO; void configure(const Config& config); - void run(const render::RenderContextPointer& renderContext, const Inputs& inputs); + void run(const render::RenderContextPointer& renderContext, const Input& input, Output& output); ToneMappingEffect _toneMappingEffect; }; diff --git a/libraries/render/src/render/ResampleTask.cpp b/libraries/render/src/render/ResampleTask.cpp index ed4d0ddfd0..3e9bfec8da 100644 --- a/libraries/render/src/render/ResampleTask.cpp +++ b/libraries/render/src/render/ResampleTask.cpp @@ -135,3 +135,43 @@ void Upsample::run(const RenderContextPointer& renderContext, const gpu::Framebu args->_viewport = viewport; } } + +gpu::PipelinePointer UpsampleToBlitFramebuffer::_pipeline; + +void UpsampleToBlitFramebuffer::run(const RenderContextPointer& renderContext, const Input& input, gpu::FramebufferPointer& resampledFrameBuffer) { + assert(renderContext->args); + assert(renderContext->args->hasViewFrustum()); + RenderArgs* args = renderContext->args; + auto sourceFramebuffer = input; + + resampledFrameBuffer = args->_blitFramebuffer; + + if (resampledFrameBuffer != sourceFramebuffer) { + if (!_pipeline) { + gpu::ShaderPointer program = gpu::Shader::createProgram(shader::gpu::program::drawTransformUnitQuadTextureOpaque); + gpu::StatePointer state = gpu::StatePointer(new gpu::State()); + state->setDepthTest(gpu::State::DepthTest(false, false)); + _pipeline = gpu::Pipeline::create(program, state); + } + const auto bufferSize = resampledFrameBuffer->getSize(); + glm::ivec4 viewport{ 0, 0, bufferSize.x, bufferSize.y }; + + gpu::doInBatch("Upsample::run", args->_context, [&](gpu::Batch& batch) { + batch.enableStereo(false); + + batch.setFramebuffer(resampledFrameBuffer); + + batch.setViewportTransform(viewport); + batch.setProjectionTransform(glm::mat4()); + batch.resetViewTransform(); + batch.setPipeline(_pipeline); + + batch.setModelTransform(gpu::Framebuffer::evalSubregionTexcoordTransform(bufferSize, viewport)); + batch.setResourceTexture(0, sourceFramebuffer->getRenderBuffer(0)); + batch.draw(gpu::TRIANGLE_STRIP, 4); + }); + + // Set full final viewport + args->_viewport = viewport; + } +} diff --git a/libraries/render/src/render/ResampleTask.h b/libraries/render/src/render/ResampleTask.h index 25f9c6a3e9..e62b76e6d0 100644 --- a/libraries/render/src/render/ResampleTask.h +++ b/libraries/render/src/render/ResampleTask.h @@ -67,6 +67,20 @@ namespace render { gpu::FramebufferPointer getResampledFrameBuffer(const gpu::FramebufferPointer& sourceFramebuffer); }; + + class UpsampleToBlitFramebuffer { + public: + using Input = gpu::FramebufferPointer; + using JobModel = Job::ModelIO; + + UpsampleToBlitFramebuffer() {} + + void run(const RenderContextPointer& renderContext, const Input& input, gpu::FramebufferPointer& resampledFrameBuffer); + + protected: + + static gpu::PipelinePointer _pipeline; + }; } #endif // hifi_render_ResampleTask_h diff --git a/scripts/developer/utilities/lib/prop/PropGroup.qml b/scripts/developer/utilities/lib/prop/PropGroup.qml index 22facb71c6..848ff8b288 100644 --- a/scripts/developer/utilities/lib/prop/PropGroup.qml +++ b/scripts/developer/utilities/lib/prop/PropGroup.qml @@ -17,6 +17,8 @@ PropFolderPanel { Global { id: global } id: root + property var rootObject: {} + property alias propItemsPanel: root.panelFrameContent // Prop Group is designed to author an array of ProItems, they are defined with an array of the tuplets describing each individual item: @@ -79,12 +81,24 @@ PropFolderPanel { }) } break; case 'object': { - var component = Qt.createComponent("PropItem.qml"); + console.log('Item is an object, create PropGroup: ' + JSON.stringify(proItem.object[proItem.property])); + var itemRootObject = proItem.object[proItem.property]; + var itemLabel = proItem.property; + var itemDepth = root.indentDepth + 1; + if (Array.isArray(itemRootObject)) { + if (objectItem.length > 1) { + itemLabel = itemLabel + " " + objectItem.length + } else { + itemLabel = itemLabel + " " + objectItem.length + itemRootObject = itemRootObject[0]; + } + } + var component = Qt.createComponent("PropGroup.qml"); component.createObject(propItemsContainer, { - "label": proItem.property, - "object": proItem.object, - "property": proItem.property, - }) + "label": itemLabel, + "rootObject":itemRootObject, + "indentDepth": itemDepth, + }) } break; case 'printLabel': { var component = Qt.createComponent("PropItem.qml"); @@ -110,19 +124,46 @@ PropFolderPanel { function populateFromObjectProps(object) { var propsModel = [] - var props = Object.keys(object); + if (Array.isArray(object)) { + if (object.length <= 1) { + object = object[0]; + } + } + + var props = Object.keys(object); for (var p in props) { var o = {}; o["object"] = object o["property"] = props[p]; // o["readOnly"] = true; - o["type"] = "string"; - propsModel.push(o) + + var thePropThing = object[props[p]]; + if ((thePropThing !== undefined) && (thePropThing !== null)) { + var theType = typeof(thePropThing) + switch(theType) { + case 'object': { + o["type"] = "object"; + propsModel.push(o) + } break; + default: { + o["type"] = "string"; + propsModel.push(o) + } break; + } + + } else { + o["type"] = "string"; + propsModel.push(o) + } } + root.updatePropItems(root.propItemsPanel, propsModel); } Component.onCompleted: { + if (root.rootObject !== null) { + populateFromObjectProps(root.rootObject) + } } } diff --git a/scripts/developer/utilities/lib/prop/PropScalar.qml b/scripts/developer/utilities/lib/prop/PropScalar.qml index 33e1bfc958..ae86c6ef81 100644 --- a/scripts/developer/utilities/lib/prop/PropScalar.qml +++ b/scripts/developer/utilities/lib/prop/PropScalar.qml @@ -20,17 +20,22 @@ PropItem { property bool integral: false property var numDigits: 2 - property alias valueVar : sliderControl.value + property alias min: sliderControl.minimumValue property alias max: sliderControl.maximumValue property bool showValue: true - signal valueChanged(real value) - Component.onCompleted: { - valueVar = root.valueVarGetter(); - } + } + + property var sourceValueVar: root.valueVarGetter() + + function applyValueVarFromWidgets(value) { + if (!root.readOnly) { + root.valueVarSetter(value) + } + } PropLabel { id: valueLabel @@ -42,7 +47,7 @@ PropItem { horizontalAlignment: global.valueTextAlign height: global.slimHeight - text: root.valueVarGetter().toFixed(root.integral ? 0 : root.numDigits) + text: root.sourceValueVar.toFixed(root.integral ? 0 : root.numDigits) background: Rectangle { color: global.color @@ -59,8 +64,8 @@ PropItem { anchors.left: valueLabel.right anchors.right: root.right anchors.verticalCenter: root.verticalCenter - - onValueChanged: { if (!root.readOnly) { root.valueVarSetter(value)} } + value: root.sourceValueVar + onValueChanged: { applyValueVarFromWidgets(value) } } diff --git a/scripts/developer/utilities/render/luci/Platform.qml b/scripts/developer/utilities/render/luci/Platform.qml index 9c5ffda070..eaa4766b32 100644 --- a/scripts/developer/utilities/render/luci/Platform.qml +++ b/scripts/developer/utilities/render/luci/Platform.qml @@ -23,46 +23,31 @@ Column { id: computer label: "Computer" isUnfold: true - - Component.onCompleted: { - computer.populateFromObjectProps(JSON.parse(PlatformInfo.getComputer())) - } + rootObject:JSON.parse(PlatformInfo.getComputer()) } Prop.PropGroup { id: cpu label: "CPU" isUnfold: true - - Component.onCompleted: { - cpu.populateFromObjectProps(JSON.parse(PlatformInfo.getCPU(0))) - } + rootObject:JSON.parse(PlatformInfo.getPlatform()).cpus } Prop.PropGroup { id: memory label: "Memory" isUnfold: true - - Component.onCompleted: { - memory.populateFromObjectProps(JSON.parse(PlatformInfo.getMemory())) - } + rootObject:JSON.parse(PlatformInfo.getMemory()) } Prop.PropGroup { id: gpu label: "GPU" isUnfold: true - - Component.onCompleted: { - gpu.populateFromObjectProps(JSON.parse(PlatformInfo.getGPU(0))) - } + rootObject:JSON.parse(PlatformInfo.getPlatform()).gpus } Prop.PropGroup { id: display label: "Display" isUnfold: true - - Component.onCompleted: { - display.populateFromObjectProps(JSON.parse(PlatformInfo.getDisplay(0))) - } + rootObject:JSON.parse(PlatformInfo.getPlatform()).displays } } diff --git a/scripts/developer/utilities/render/luci/RenderSettings.qml b/scripts/developer/utilities/render/luci/RenderSettings.qml index 906c117b3a..bd76964070 100644 --- a/scripts/developer/utilities/render/luci/RenderSettings.qml +++ b/scripts/developer/utilities/render/luci/RenderSettings.qml @@ -30,5 +30,12 @@ Column { object: Render property: "shadowsEnabled" } + Prop.PropScalar { + label: "Viewport Resolution Scale" + object: Render + property: "viewportResolutionScale" + min: 0.25 + max: 1.5 + } }