From ca5c7e3904a9f6d150a35d10b16f70d84d5a7106 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Fri, 26 Apr 2019 12:56:01 -0700 Subject: [PATCH 1/8] runtime switch for deferred/forward rendering --- interface/src/Application.cpp | 5 +- interface/src/SecondaryCamera.cpp | 4 +- interface/src/SecondaryCamera.h | 2 +- interface/src/graphics/GraphicsEngine.cpp | 6 +- interface/src/graphics/GraphicsEngine.h | 2 +- libraries/render-utils/src/RenderViewTask.cpp | 18 +-- libraries/render-utils/src/RenderViewTask.h | 5 +- libraries/task/src/task/Config.cpp | 8 ++ libraries/task/src/task/Config.h | 12 ++ libraries/task/src/task/Task.h | 108 ++++++++++++++---- 10 files changed, 129 insertions(+), 41 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 4e2e4e8de1..d0fd406842 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -243,11 +243,8 @@ #include "webbrowser/WebBrowserSuggestionsEngine.h" #include - #include "AboutUtil.h" -#include - #if defined(Q_OS_WIN) #include @@ -2979,7 +2976,7 @@ void Application::initializeDisplayPlugins() { void Application::initializeRenderEngine() { // FIXME: on low end systems os the shaders take up to 1 minute to compile, so we pause the deadlock watchdog thread. DeadlockWatchdogThread::withPause([&] { - _graphicsEngine.initializeRender(DISABLE_DEFERRED); + _graphicsEngine.initializeRender(); DependencyManager::get()->registerKeyboardHighlighting(); }); } diff --git a/interface/src/SecondaryCamera.cpp b/interface/src/SecondaryCamera.cpp index da2874a3f4..704d7963e7 100644 --- a/interface/src/SecondaryCamera.cpp +++ b/interface/src/SecondaryCamera.cpp @@ -272,10 +272,10 @@ public: } }; -void SecondaryCameraRenderTask::build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, bool isDeferred) { +void SecondaryCameraRenderTask::build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor) { const auto cachedArg = task.addJob("SecondaryCamera"); - task.addJob("RenderSecondView", cullFunctor, isDeferred, render::ItemKey::TAG_BITS_1, render::ItemKey::TAG_BITS_1); + task.addJob("RenderSecondView", cullFunctor, render::ItemKey::TAG_BITS_1, render::ItemKey::TAG_BITS_1); task.addJob("EndSecondaryCamera", cachedArg); } \ No newline at end of file diff --git a/interface/src/SecondaryCamera.h b/interface/src/SecondaryCamera.h index 941ccc5f93..463034527a 100644 --- a/interface/src/SecondaryCamera.h +++ b/interface/src/SecondaryCamera.h @@ -65,7 +65,7 @@ public: using JobModel = render::Task::Model; SecondaryCameraRenderTask() {} void configure(const Config& config) {} - void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, bool isDeferred = true); + void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor); }; #endif diff --git a/interface/src/graphics/GraphicsEngine.cpp b/interface/src/graphics/GraphicsEngine.cpp index 267822baf2..4f8b86cc0c 100644 --- a/interface/src/graphics/GraphicsEngine.cpp +++ b/interface/src/graphics/GraphicsEngine.cpp @@ -65,15 +65,15 @@ void GraphicsEngine::initializeGPU(GLWidget* glwidget) { DependencyManager::get()->setGPUContext(_gpuContext); } -void GraphicsEngine::initializeRender(bool disableDeferred) { +void GraphicsEngine::initializeRender() { // Set up the render engine render::CullFunctor cullFunctor = LODManager::shouldRender; _renderEngine->addJob("UpdateScene"); #ifndef Q_OS_ANDROID - _renderEngine->addJob("SecondaryCameraJob", cullFunctor, !disableDeferred); + _renderEngine->addJob("SecondaryCameraJob", cullFunctor); #endif - _renderEngine->addJob("RenderMainView", cullFunctor, !disableDeferred, render::ItemKey::TAG_BITS_0, render::ItemKey::TAG_BITS_0); + _renderEngine->addJob("RenderMainView", cullFunctor, render::ItemKey::TAG_BITS_0, render::ItemKey::TAG_BITS_0); _renderEngine->load(); _renderEngine->registerScene(_renderScene); diff --git a/interface/src/graphics/GraphicsEngine.h b/interface/src/graphics/GraphicsEngine.h index f0b88d2459..dccb098d5e 100644 --- a/interface/src/graphics/GraphicsEngine.h +++ b/interface/src/graphics/GraphicsEngine.h @@ -44,7 +44,7 @@ public: ~GraphicsEngine(); void initializeGPU(GLWidget*); - void initializeRender(bool disableDeferred); + void initializeRender(); void startup(); void shutdown(); diff --git a/libraries/render-utils/src/RenderViewTask.cpp b/libraries/render-utils/src/RenderViewTask.cpp index 7230635060..61823cf01c 100644 --- a/libraries/render-utils/src/RenderViewTask.cpp +++ b/libraries/render-utils/src/RenderViewTask.cpp @@ -15,7 +15,9 @@ #include "RenderDeferredTask.h" #include "RenderForwardTask.h" -void RenderViewTask::build(JobModel& task, const render::Varying& input, render::Varying& output, render::CullFunctor cullFunctor, bool isDeferred, uint8_t tagBits, uint8_t tagMask) { +#include + +void RenderViewTask::build(JobModel& task, const render::Varying& input, render::Varying& output, render::CullFunctor cullFunctor, uint8_t tagBits, uint8_t tagMask) { const auto items = task.addJob("FetchCullSort", cullFunctor, tagBits, tagMask); assert(items.canCast()); @@ -25,17 +27,19 @@ void RenderViewTask::build(JobModel& task, const render::Varying& input, render: // Assemble the lighting stages current frames const auto lightingStageFramesAndZones = task.addJob("AssembleStages", items); - if (isDeferred) { + if (!DISABLE_DEFERRED) { // Warning : the cull functor passed to the shadow pass should only be testing for LOD culling. If frustum culling // is performed, then casters not in the view frustum will be removed, which is not what we wish. const auto shadowTaskIn = RenderShadowTask::Input(lightingStageFramesAndZones.get().get0()[0], lightingModel).asVarying(); - const auto shadowTaskOut = task.addJob("RenderShadowTask", shadowTaskIn, cullFunctor, tagBits, tagMask); + const auto shadowTaskOut = task.addSwitchJob("RenderShadowTask", 0, shadowTaskIn, cullFunctor, tagBits, tagMask); - const auto renderInput = RenderDeferredTask::Input(items, lightingModel, lightingStageFramesAndZones, shadowTaskOut).asVarying(); - task.addJob("RenderDeferredTask", renderInput); + const auto renderDeferredInput = RenderDeferredTask::Input(items, lightingModel, lightingStageFramesAndZones, shadowTaskOut).asVarying(); + task.addSwitchJob("RenderDeferredTask", 0, renderDeferredInput); + + const auto renderForwardInput = RenderForwardTask::Input(items, lightingModel, lightingStageFramesAndZones).asVarying(); + task.addSwitchJob("RenderForwardTask", 1, renderForwardInput); } else { const auto renderInput = RenderForwardTask::Input(items, lightingModel, lightingStageFramesAndZones).asVarying(); - task.addJob("Forward", renderInput); + task.addJob("RenderForwardTask", renderInput); } } - diff --git a/libraries/render-utils/src/RenderViewTask.h b/libraries/render-utils/src/RenderViewTask.h index 5da3d18474..b4d9326944 100644 --- a/libraries/render-utils/src/RenderViewTask.h +++ b/libraries/render-utils/src/RenderViewTask.h @@ -19,11 +19,12 @@ class RenderViewTask { public: using Input = RenderFetchCullSortTask::Output; - using JobModel = render::Task::ModelI; + using JobModel = render::Task::ModelIS; RenderViewTask() {} - void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, bool isDeferred, uint8_t tagBits = 0x00, uint8_t tagMask = 0x00); + void configure(const render::SwitchConfig& configuration) {} + void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, uint8_t tagBits = 0x00, uint8_t tagMask = 0x00); }; diff --git a/libraries/task/src/task/Config.cpp b/libraries/task/src/task/Config.cpp index 5e8e4b246d..c836d06717 100644 --- a/libraries/task/src/task/Config.cpp +++ b/libraries/task/src/task/Config.cpp @@ -133,3 +133,11 @@ JobConfig* TaskConfig::getJobConfig(const std::string& jobPath) const { return found; } } + +void SwitchConfig::setSwitchIndex(uint8_t index) { + if (_switchIndex != index) { + _switchIndex = index; + // We can re-use this signal here + emit dirtyEnabled(); + } +} \ No newline at end of file diff --git a/libraries/task/src/task/Config.h b/libraries/task/src/task/Config.h index 486b28b6b9..d158e16eec 100644 --- a/libraries/task/src/task/Config.h +++ b/libraries/task/src/task/Config.h @@ -262,6 +262,18 @@ public slots: void refresh(); }; +class SwitchConfig : public TaskConfig { + Q_OBJECT + Q_PROPERTY(bool switchIndex READ getSwitchIndex WRITE setSwitchIndex NOTIFY dirtyEnabled) + +public: + uint8_t getSwitchIndex() const { return _switchIndex; } + void setSwitchIndex(uint8_t index); + +protected: + uint8_t _switchIndex { 0 }; +}; + } #endif // hifi_task_Config_h diff --git a/libraries/task/src/task/Task.h b/libraries/task/src/task/Task.h index b74986235e..e4f7e789f4 100644 --- a/libraries/task/src/task/Task.h +++ b/libraries/task/src/task/Task.h @@ -15,6 +15,8 @@ #include "Config.h" #include "Varying.h" +#include + namespace task { class JobConcept; @@ -244,25 +246,6 @@ public: const Varying getOutput() const override { return _output; } Varying& editInput() override { return _input; } - typename Jobs::iterator editJob(std::string name) { - typename Jobs::iterator jobIt; - for (jobIt = _jobs.begin(); jobIt != _jobs.end(); ++jobIt) { - if (jobIt->getName() == name) { - return jobIt; - } - } - return jobIt; - } - typename Jobs::const_iterator getJob(std::string name) const { - typename Jobs::const_iterator jobIt; - for (jobIt = _jobs.begin(); jobIt != _jobs.end(); ++jobIt) { - if (jobIt->getName() == name) { - return jobIt; - } - } - return jobIt; - } - TaskConcept(const std::string& name, const Varying& input, QConfigPointer config) : Concept(name, config), _input(input) {} // Create a new job in the container's queue; returns the job's output @@ -331,7 +314,7 @@ public: return Concept::_config; } - void applyConfiguration() override { + virtual void applyConfiguration() override { TimeProfiler probe("configure::" + JobConcept::getName()); jobConfigure(_data, *std::static_pointer_cast(Concept::_config)); for (auto& job : TaskConcept::_jobs) { @@ -339,7 +322,7 @@ public: } } - void run(const ContextPointer& jobContext) override { + virtual void run(const ContextPointer& jobContext) override { auto config = std::static_pointer_cast(Concept::_config); if (config->isEnabled()) { for (auto job : TaskConcept::_jobs) { @@ -357,6 +340,81 @@ public: template using ModelO = TaskModel; template using ModelIO = TaskModel; + template class SwitchTaskModel : public TaskModel { + public: + using Input = I; + + std::unordered_map _jobsSwitch; + + SwitchTaskModel(const std::string& name, const Varying& input, QConfigPointer config) : TaskModel(name, input, config) {} + + template + static std::shared_ptr create(const std::string& name, const Varying& input, A&&... args) { + auto model = std::make_shared(name, input, std::make_shared()); + + { + TimeProfiler probe("build::" + model->getName()); + model->_data.build(*(model), model->_input, model->_output, std::forward(args)...); + } + // Recreate the Config to use the templated type + model->createConfiguration(); + model->applyConfiguration(); + + return model; + } + + template + static std::shared_ptr create(const std::string& name, A&&... args) { + const auto input = Varying(Input()); + return create(name, input, std::forward(args)...); + } + + void applyConfiguration() override { + TaskModel::applyConfiguration(); + + for (auto& jobs : _jobsSwitch) { + for (auto& job : jobs.second) { + job.applyConfiguration(); + } + } + } + + void run(const ContextPointer& jobContext) override { + auto config = std::static_pointer_cast(Concept::_config); + if (config->isEnabled()) { + // First we run all the setup jobs + TaskModel::run(jobContext); + + // Then we run the branching jobs + auto jobsIt = _jobsSwitch.find(config->getSwitchIndex()); + if (jobsIt != _jobsSwitch.end()) { + for (auto job : jobsIt->second) { + job.run(jobContext); + if (jobContext->taskFlow.doAbortTask()) { + jobContext->taskFlow.reset(); + return; + } + } + } + } + } + + template const Varying addSwitchJob(std::string name, uint8_t index, const Varying& input, NA&&... args) { + auto& jobs = _jobsSwitch[index]; + jobs.emplace_back((NT::JobModel::create(name, input, std::forward(args)...))); + + // Conect the child config to this task's config + std::static_pointer_cast(Concept::getConfiguration())->connectChildConfig(jobs.back().getConfiguration(), name); + + return jobs.back().getOutput(); + } + template const Varying addSwitchJob(std::string name, uint8_t index, NA&&... args) { + const auto input = Varying(typename NT::JobModel::Input()); + return addJob(name, index, input, std::forward(args)...); + } + }; + template using ModelIS = SwitchTaskModel; + // Create a new job in the Task's queue; returns the job's output template const Varying addJob(std::string name, const Varying& input, A&&... args) { return std::static_pointer_cast(JobType::_concept)->template addJob(name, input, std::forward(args)...); @@ -365,6 +423,13 @@ public: const auto input = Varying(typename T::JobModel::Input()); return std::static_pointer_cast(JobType::_concept)->template addJob(name, input, std::forward(args)...); } + template const Varying addSwitchJob(std::string name, uint8_t index, const Varying& input, A&&... args) { + return std::static_pointer_cast(JobType::_concept)->template addSwitchJob(name, index, input, std::forward(args)...); + } + template const Varying addSwitchJob(std::string name, uint8_t index, A&&... args) { + const auto input = Varying(typename T::JobModel::Input()); + return std::static_pointer_cast(JobType::_concept)->template addSwitchJob(name, index, input, std::forward(args)...); + } std::shared_ptr getConfiguration() { return std::static_pointer_cast(JobType::_concept->getConfiguration()); @@ -407,6 +472,7 @@ protected: #define Task_DeclareTypeAliases(ContextType, TimeProfiler) \ using JobConfig = task::JobConfig; \ using TaskConfig = task::TaskConfig; \ + using SwitchConfig = task::SwitchConfig; \ template using PersistentConfig = task::PersistentConfig; \ using Job = task::Job; \ using Task = task::Task; \ From 4a02ab4fe2e20f1ba179017546e7ee3a7da3ec4e Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Mon, 29 Apr 2019 14:01:09 -0700 Subject: [PATCH 2/8] move switch logic around --- libraries/render-utils/src/RenderViewTask.cpp | 34 ++-- libraries/render-utils/src/RenderViewTask.h | 27 ++- libraries/task/src/task/Config.cpp | 14 +- libraries/task/src/task/Config.h | 32 ++-- libraries/task/src/task/Task.h | 174 ++++++++++++------ 5 files changed, 187 insertions(+), 94 deletions(-) diff --git a/libraries/render-utils/src/RenderViewTask.cpp b/libraries/render-utils/src/RenderViewTask.cpp index 61823cf01c..a38769165b 100644 --- a/libraries/render-utils/src/RenderViewTask.cpp +++ b/libraries/render-utils/src/RenderViewTask.cpp @@ -10,16 +10,34 @@ // #include "RenderViewTask.h" -#include "AssembleLightingStageTask.h" #include "RenderShadowTask.h" #include "RenderDeferredTask.h" #include "RenderForwardTask.h" #include +void RenderShadowsAndDeferredTask::build(JobModel& task, const render::Varying& input, render::Varying& output, render::CullFunctor cullFunctor, uint8_t tagBits, uint8_t tagMask) { + const auto items = input.getN(0); + const auto lightingModel = input.getN(1); + const auto lightingStageFramesAndZones = input.getN(2); + + // Warning : the cull functor passed to the shadow pass should only be testing for LOD culling. If frustum culling + // is performed, then casters not in the view frustum will be removed, which is not what we wish. + const auto shadowTaskIn = RenderShadowTask::Input(lightingStageFramesAndZones.get().get0()[0], lightingModel).asVarying(); + const auto shadowTaskOut = task.addJob("RenderShadowTask", shadowTaskIn, cullFunctor, tagBits, tagMask); + + const auto renderDeferredInput = RenderDeferredTask::Input(items, lightingModel, lightingStageFramesAndZones, shadowTaskOut).asVarying(); + task.addJob("RenderDeferredTask", renderDeferredInput); +} + +void DeferredForwardSwitchJob::build(JobModel& task, const render::Varying& input, render::Varying& output, render::CullFunctor cullFunctor, uint8_t tagBits, uint8_t tagMask) { + task.addBranch("RenderShadowsAndDeferredTask", 0, input, cullFunctor, tagBits, tagMask); + + task.addBranch("RenderForwardTask", 1, input); +} + void RenderViewTask::build(JobModel& task, const render::Varying& input, render::Varying& output, render::CullFunctor cullFunctor, uint8_t tagBits, uint8_t tagMask) { const auto items = task.addJob("FetchCullSort", cullFunctor, tagBits, tagMask); - assert(items.canCast()); // Issue the lighting model, aka the big global settings for the view const auto lightingModel = task.addJob("LightingModel"); @@ -28,16 +46,8 @@ void RenderViewTask::build(JobModel& task, const render::Varying& input, render: const auto lightingStageFramesAndZones = task.addJob("AssembleStages", items); if (!DISABLE_DEFERRED) { - // Warning : the cull functor passed to the shadow pass should only be testing for LOD culling. If frustum culling - // is performed, then casters not in the view frustum will be removed, which is not what we wish. - const auto shadowTaskIn = RenderShadowTask::Input(lightingStageFramesAndZones.get().get0()[0], lightingModel).asVarying(); - const auto shadowTaskOut = task.addSwitchJob("RenderShadowTask", 0, shadowTaskIn, cullFunctor, tagBits, tagMask); - - const auto renderDeferredInput = RenderDeferredTask::Input(items, lightingModel, lightingStageFramesAndZones, shadowTaskOut).asVarying(); - task.addSwitchJob("RenderDeferredTask", 0, renderDeferredInput); - - const auto renderForwardInput = RenderForwardTask::Input(items, lightingModel, lightingStageFramesAndZones).asVarying(); - task.addSwitchJob("RenderForwardTask", 1, renderForwardInput); + const auto deferredForwardIn = DeferredForwardSwitchJob::Input(items, lightingModel, lightingStageFramesAndZones).asVarying(); + task.addJob("DeferredForwardSwitch", deferredForwardIn, cullFunctor, tagBits, tagMask); } else { const auto renderInput = RenderForwardTask::Input(items, lightingModel, lightingStageFramesAndZones).asVarying(); task.addJob("RenderForwardTask", renderInput); diff --git a/libraries/render-utils/src/RenderViewTask.h b/libraries/render-utils/src/RenderViewTask.h index b4d9326944..cdb56a2189 100644 --- a/libraries/render-utils/src/RenderViewTask.h +++ b/libraries/render-utils/src/RenderViewTask.h @@ -15,15 +15,38 @@ #include #include +#include "AssembleLightingStageTask.h" + +class RenderShadowsAndDeferredTask { +public: + using Input = render::VaryingSet3; + using JobModel = render::Task::ModelI; + + RenderShadowsAndDeferredTask() {} + + void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, uint8_t tagBits, uint8_t tagMask); + +}; + +class DeferredForwardSwitchJob { +public: + using Input = render::VaryingSet3; + using JobModel = render::Switch::ModelI; + + DeferredForwardSwitchJob() {} + + void configure(const render::SwitchConfig& config) {} + void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, uint8_t tagBits, uint8_t tagMask); + +}; class RenderViewTask { public: using Input = RenderFetchCullSortTask::Output; - using JobModel = render::Task::ModelIS; + using JobModel = render::Task::ModelI; RenderViewTask() {} - void configure(const render::SwitchConfig& configuration) {} void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, uint8_t tagBits = 0x00, uint8_t tagMask = 0x00); }; diff --git a/libraries/task/src/task/Config.cpp b/libraries/task/src/task/Config.cpp index c836d06717..79e0b9f7fb 100644 --- a/libraries/task/src/task/Config.cpp +++ b/libraries/task/src/task/Config.cpp @@ -38,7 +38,7 @@ void JobConfig::setPresetList(const QJsonObject& object) { } } -void TaskConfig::connectChildConfig(QConfigPointer childConfig, const std::string& name) { +void JobConfig::connectChildConfig(std::shared_ptr childConfig, const std::string& name) { childConfig->setParent(this); childConfig->setObjectName(name.c_str()); @@ -52,7 +52,7 @@ void TaskConfig::connectChildConfig(QConfigPointer childConfig, const std::strin } } -void TaskConfig::transferChildrenConfigs(QConfigPointer source) { +void JobConfig::transferChildrenConfigs(std::shared_ptr source) { if (!source) { return; } @@ -70,13 +70,13 @@ void TaskConfig::transferChildrenConfigs(QConfigPointer source) { } } -void TaskConfig::refresh() { +void JobConfig::refresh() { if (QThread::currentThread() != thread()) { BLOCKING_INVOKE_METHOD(this, "refresh"); return; } - _task->applyConfiguration(); + _jobConcept->applyConfiguration(); } TaskConfig* TaskConfig::getRootConfig(const std::string& jobPath, std::string& jobName) const { @@ -134,9 +134,9 @@ JobConfig* TaskConfig::getJobConfig(const std::string& jobPath) const { } } -void SwitchConfig::setSwitchIndex(uint8_t index) { - if (_switchIndex != index) { - _switchIndex = index; +void SwitchConfig::setBranch(uint8_t branch) { + if (_branch != branch) { + _branch = branch; // We can re-use this signal here emit dirtyEnabled(); } diff --git a/libraries/task/src/task/Config.h b/libraries/task/src/task/Config.h index d158e16eec..891970006d 100644 --- a/libraries/task/src/task/Config.h +++ b/libraries/task/src/task/Config.h @@ -154,6 +154,11 @@ public: */ Q_INVOKABLE virtual QObject* getSubConfig(int i) const { return nullptr; } + void connectChildConfig(std::shared_ptr childConfig, const std::string& name); + void transferChildrenConfigs(std::shared_ptr source); + + JobConcept* _jobConcept; + public slots: /**jsdoc @@ -162,6 +167,11 @@ public slots: */ void load(const QJsonObject& val) { qObjectFromJsonValue(val, *this); emit loaded(); } + /**jsdoc + * @function Render.refresh + */ + void refresh(); + signals: /**jsdoc @@ -248,30 +258,18 @@ public: auto subs = getSubConfigs(); return ((i < 0 || i >= subs.size()) ? nullptr : subs[i]); } - - void connectChildConfig(QConfigPointer childConfig, const std::string& name); - void transferChildrenConfigs(QConfigPointer source); - - JobConcept* _task; - -public slots: - - /**jsdoc - * @function Render.refresh - */ - void refresh(); }; -class SwitchConfig : public TaskConfig { +class SwitchConfig : public JobConfig { Q_OBJECT - Q_PROPERTY(bool switchIndex READ getSwitchIndex WRITE setSwitchIndex NOTIFY dirtyEnabled) + Q_PROPERTY(bool branch READ getBranch WRITE setBranch NOTIFY dirtyEnabled) public: - uint8_t getSwitchIndex() const { return _switchIndex; } - void setSwitchIndex(uint8_t index); + uint8_t getBranch() const { return _branch; } + void setBranch(uint8_t index); protected: - uint8_t _switchIndex { 0 }; + uint8_t _branch { 0 }; }; } diff --git a/libraries/task/src/task/Task.h b/libraries/task/src/task/Task.h index e4f7e789f4..87fb21d59b 100644 --- a/libraries/task/src/task/Task.h +++ b/libraries/task/src/task/Task.h @@ -177,6 +177,7 @@ public: template using ModelO = Model; template using ModelIO = Model; + Job() {} Job(const ConceptPointer& concept) : _concept(concept) {} virtual ~Job() = default; @@ -304,7 +305,7 @@ public: // swap Concept::_config = config; // Capture this - std::static_pointer_cast(Concept::_config)->_task = this; + Concept::_config->_jobConcept = this; } QConfigPointer& getConfiguration() override { @@ -314,7 +315,7 @@ public: return Concept::_config; } - virtual void applyConfiguration() override { + void applyConfiguration() override { TimeProfiler probe("configure::" + JobConcept::getName()); jobConfigure(_data, *std::static_pointer_cast(Concept::_config)); for (auto& job : TaskConcept::_jobs) { @@ -322,7 +323,7 @@ public: } } - virtual void run(const ContextPointer& jobContext) override { + void run(const ContextPointer& jobContext) override { auto config = std::static_pointer_cast(Concept::_config); if (config->isEnabled()) { for (auto job : TaskConcept::_jobs) { @@ -340,17 +341,86 @@ public: template using ModelO = TaskModel; template using ModelIO = TaskModel; - template class SwitchTaskModel : public TaskModel { + // Create a new job in the Task's queue; returns the job's output + template const Varying addJob(std::string name, const Varying& input, A&&... args) { + return std::static_pointer_cast(JobType::_concept)->template addJob(name, input, std::forward(args)...); + } + template const Varying addJob(std::string name, A&&... args) { + const auto input = Varying(typename T::JobModel::Input()); + return std::static_pointer_cast(JobType::_concept)->template addJob(name, input, std::forward(args)...); + } + + std::shared_ptr getConfiguration() { + return std::static_pointer_cast(JobType::_concept->getConfiguration()); + } +}; + + +// A Switch is a specialized job to run a collection of other jobs and switch between different branches at run time +// It can be created on any type T by aliasing the type JobModel in the class T +// using JobModel = Switch::Model +// The class T is expected to have a "build" method acting as a constructor. +// The build method is where child Jobs can be added internally to the branches of the switch +// where the input of the switch can be setup to feed the child jobs +// and where the output of the switch is defined +template +class Switch : public Job { +public: + using Context = JC; + using TimeProfiler = TP; + using ContextPointer = std::shared_ptr; + using Config = SwitchConfig; + using JobType = Job; + using None = typename JobType::None; + using Concept = typename JobType::Concept; + using ConceptPointer = typename JobType::ConceptPointer; + using Branches = std::unordered_map; + + Switch(ConceptPointer concept) : JobType(concept) {} + + class SwitchConcept : public Concept { public: + Varying _input; + Varying _output; + Branches _branches; + + const Varying getInput() const override { return _input; } + const Varying getOutput() const override { return _output; } + Varying& editInput() override { return _input; } + + SwitchConcept(const std::string& name, const Varying& input, QConfigPointer config) : Concept(name, config), _input(input) {} + + template const Varying addBranch(std::string name, uint8_t index, const Varying& input, NA&&... args) { + auto& branch = _branches[index]; + branch = JobType(NT::JobModel::create(name, input, std::forward(args)...)); + + // Conect the child config to this task's config + std::static_pointer_cast(Concept::getConfiguration())->connectChildConfig(branch.getConfiguration(), name); + + return branch.getOutput(); + } + template const Varying addBranch(std::string name, uint8_t index, NA&&... args) { + const auto input = Varying(typename NT::JobModel::Input()); + return addBranch(name, index, input, std::forward(args)...); + } + }; + + template class SwitchModel : public SwitchConcept { + public: + using Data = T; using Input = I; + using Output = O; - std::unordered_map _jobsSwitch; + Data _data; - SwitchTaskModel(const std::string& name, const Varying& input, QConfigPointer config) : TaskModel(name, input, config) {} + SwitchModel(const std::string& name, const Varying& input, QConfigPointer config) : + SwitchConcept(name, input, config), + _data(Data()) { + } template - static std::shared_ptr create(const std::string& name, const Varying& input, A&&... args) { - auto model = std::make_shared(name, input, std::make_shared()); + static std::shared_ptr create(const std::string& name, const Varying& input, A&&... args) { + auto model = std::make_shared(name, input, std::make_shared()); { TimeProfiler probe("build::" + model->getName()); @@ -364,78 +434,69 @@ public: } template - static std::shared_ptr create(const std::string& name, A&&... args) { + static std::shared_ptr create(const std::string& name, A&&... args) { const auto input = Varying(Input()); return create(name, input, std::forward(args)...); } - void applyConfiguration() override { - TaskModel::applyConfiguration(); + void createConfiguration() { + // A brand new config + auto config = std::make_shared(); + // Make sure we transfer the former children configs to the new config + config->transferChildrenConfigs(Concept::_config); + // swap + Concept::_config = config; + // Capture this + Concept::_config->_jobConcept = this; + } - for (auto& jobs : _jobsSwitch) { - for (auto& job : jobs.second) { - job.applyConfiguration(); - } + QConfigPointer& getConfiguration() override { + if (!Concept::_config) { + createConfiguration(); + } + return Concept::_config; + } + + void applyConfiguration() override { + TimeProfiler probe("configure::" + JobConcept::getName()); + jobConfigure(_data, *std::static_pointer_cast(Concept::_config)); + for (auto& branch : _branches) { + branch.second.applyConfiguration(); } } void run(const ContextPointer& jobContext) override { auto config = std::static_pointer_cast(Concept::_config); if (config->isEnabled()) { - // First we run all the setup jobs - TaskModel::run(jobContext); - - // Then we run the branching jobs - auto jobsIt = _jobsSwitch.find(config->getSwitchIndex()); - if (jobsIt != _jobsSwitch.end()) { - for (auto job : jobsIt->second) { - job.run(jobContext); - if (jobContext->taskFlow.doAbortTask()) { - jobContext->taskFlow.reset(); - return; - } + auto jobsIt = _branches.find(config->getBranch()); + if (jobsIt != _branches.end()) { + jobsIt->second.run(jobContext); + if (jobContext->taskFlow.doAbortTask()) { + jobContext->taskFlow.reset(); + return; } } } } - - template const Varying addSwitchJob(std::string name, uint8_t index, const Varying& input, NA&&... args) { - auto& jobs = _jobsSwitch[index]; - jobs.emplace_back((NT::JobModel::create(name, input, std::forward(args)...))); - - // Conect the child config to this task's config - std::static_pointer_cast(Concept::getConfiguration())->connectChildConfig(jobs.back().getConfiguration(), name); - - return jobs.back().getOutput(); - } - template const Varying addSwitchJob(std::string name, uint8_t index, NA&&... args) { - const auto input = Varying(typename NT::JobModel::Input()); - return addJob(name, index, input, std::forward(args)...); - } }; - template using ModelIS = SwitchTaskModel; + template using Model = SwitchModel; + template using ModelI = SwitchModel; + // TODO: Switches don't support Outputs yet + //template using ModelO = SwitchModel; + //template using ModelIO = SwitchModel; - // Create a new job in the Task's queue; returns the job's output - template const Varying addJob(std::string name, const Varying& input, A&&... args) { - return std::static_pointer_cast(JobType::_concept)->template addJob(name, input, std::forward(args)...); + // Create a new job in the Switches' branches; returns the job's output + template const Varying addBranch(std::string name, uint8_t index, const Varying& input, A&&... args) { + return std::static_pointer_cast(JobType::_concept)->template addBranch(name, index, input, std::forward(args)...); } - template const Varying addJob(std::string name, A&&... args) { + template const Varying addBranch(std::string name, uint8_t index, A&&... args) { const auto input = Varying(typename T::JobModel::Input()); - return std::static_pointer_cast(JobType::_concept)->template addJob(name, input, std::forward(args)...); - } - template const Varying addSwitchJob(std::string name, uint8_t index, const Varying& input, A&&... args) { - return std::static_pointer_cast(JobType::_concept)->template addSwitchJob(name, index, input, std::forward(args)...); - } - template const Varying addSwitchJob(std::string name, uint8_t index, A&&... args) { - const auto input = Varying(typename T::JobModel::Input()); - return std::static_pointer_cast(JobType::_concept)->template addSwitchJob(name, index, input, std::forward(args)...); + return std::static_pointer_cast(JobType::_concept)->template addBranch(name, index, input, std::forward(args)...); } std::shared_ptr getConfiguration() { return std::static_pointer_cast(JobType::_concept->getConfiguration()); } - -protected: }; template @@ -475,6 +536,7 @@ protected: using SwitchConfig = task::SwitchConfig; \ template using PersistentConfig = task::PersistentConfig; \ using Job = task::Job; \ + using Switch = task::Switch; \ using Task = task::Task; \ using Engine = task::Engine; \ using Varying = task::Varying; \ From 410679b9b7adc17721b381439cc662c517f065a4 Mon Sep 17 00:00:00 2001 From: Saracen Date: Mon, 6 May 2019 00:30:32 +0100 Subject: [PATCH 3/8] Render lightmaps in the forward renderer --- .../render-utils/src/RenderPipelines.cpp | 4 +- .../src/forward_model_lightmap.slf | 71 ++++++++++++++++++ .../src/forward_model_normal_map_lightmap.slf | 74 +++++++++++++++++++ .../render-utils/forward_model_lightmap.slp | 1 + .../forward_model_normal_map_lightmap.slp | 1 + 5 files changed, 150 insertions(+), 1 deletion(-) create mode 100644 libraries/render-utils/src/forward_model_lightmap.slf create mode 100644 libraries/render-utils/src/forward_model_normal_map_lightmap.slf create mode 100644 libraries/render-utils/src/render-utils/forward_model_lightmap.slp create mode 100644 libraries/render-utils/src/render-utils/forward_model_normal_map_lightmap.slp diff --git a/libraries/render-utils/src/RenderPipelines.cpp b/libraries/render-utils/src/RenderPipelines.cpp index ac2eb8e475..2817abb4a1 100644 --- a/libraries/render-utils/src/RenderPipelines.cpp +++ b/libraries/render-utils/src/RenderPipelines.cpp @@ -228,9 +228,11 @@ void initForwardPipelines(ShapePlumber& plumber) { // Opaques addPipeline(Key::Builder().withMaterial(), program::forward_model); + addPipeline(Key::Builder().withMaterial().withLightmap(), program::forward_model_lightmap); addPipeline(Key::Builder().withMaterial().withUnlit(), program::forward_model_unlit); addPipeline(Key::Builder().withMaterial().withTangents(), program::forward_model_normal_map); - + addPipeline(Key::Builder().withMaterial().withTangents().withLightmap(), program::forward_model_normal_map_lightmap); + // Deformed Opaques addPipeline(Key::Builder().withMaterial().withDeformed(), program::forward_deformed_model); addPipeline(Key::Builder().withMaterial().withDeformed().withTangents(), program::forward_deformed_model_normal_map); diff --git a/libraries/render-utils/src/forward_model_lightmap.slf b/libraries/render-utils/src/forward_model_lightmap.slf new file mode 100644 index 0000000000..aa1d6dc3b8 --- /dev/null +++ b/libraries/render-utils/src/forward_model_lightmap.slf @@ -0,0 +1,71 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// <$_SCRIBE_FILENAME$> +// Generated on <$_SCRIBE_DATE$> +// +// Created by Sam Gateau on 2/15/2016. +// Copyright 2014 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 DefaultMaterials.slh@> +<@include graphics/Material.slh@> +<@include graphics/MaterialTextures.slh@> +<@include render-utils/ShaderConstants.h@> + +<@include ForwardGlobalLight.slh@> + +<$declareEvalLightmappedColor()$> + +<@include gpu/Transform.slh@> +<$declareStandardCameraTransform()$> + +<$declareMaterialTextures(ALBEDO, ROUGHNESS, _SCRIBE_NULL, METALLIC)$> +<$declareMaterialLightmap()$> + +layout(location=RENDER_UTILS_ATTR_POSITION_ES) in vec4 _positionES; +layout(location=RENDER_UTILS_ATTR_TEXCOORD01) in vec4 _texCoord01; +#define _texCoord0 _texCoord01.xy +#define _texCoord1 _texCoord01.zw +layout(location=RENDER_UTILS_ATTR_NORMAL_WS) in vec3 _normalWS; +layout(location=RENDER_UTILS_ATTR_COLOR) in vec4 _color; + +layout(location=0) out vec4 _fragColor0; + +void main(void) { + Material mat = getMaterial(); + BITFIELD matKey = getMaterialKey(mat); + <$fetchMaterialTexturesCoord0(matKey, _texCoord0, albedoTex, roughnessTex, _SCRIBE_NULL, metallicTex)$> + <$fetchMaterialTexturesCoord1(matKey, _texCoord1, _SCRIBE_NULL, lightmap)$> + + float opacity = 1.0; + <$evalMaterialOpacity(albedoTex.a, opacity, matKey, opacity)$>; + <$discardTransparent(opacity)$>; + + vec3 albedo = getMaterialAlbedo(mat); + <$evalMaterialAlbedo(albedoTex, albedo, matKey, albedo)$>; + albedo *= _color.rgb; + + float roughness = getMaterialRoughness(mat); + <$evalMaterialRoughness(roughnessTex, roughness, matKey, roughness)$>; + + float metallic = getMaterialMetallic(mat); + <$evalMaterialMetallic(metallicTex, metallic, matKey, metallic)$>; + + vec3 fragNormal = normalize(_normalWS); + + TransformCamera cam = getTransformCamera(); + + vec4 color = vec4(evalLightmappedColor( + cam._viewInverse, + 1.0, + 1.0, + fragNormal, + albedo, + lightmap), + opacity); + + _fragColor0 = color; +} diff --git a/libraries/render-utils/src/forward_model_normal_map_lightmap.slf b/libraries/render-utils/src/forward_model_normal_map_lightmap.slf new file mode 100644 index 0000000000..c36f3d51c6 --- /dev/null +++ b/libraries/render-utils/src/forward_model_normal_map_lightmap.slf @@ -0,0 +1,74 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// <$_SCRIBE_FILENAME$> +// Generated on <$_SCRIBE_DATE$> +// +// Created by Sam Gateau on 2/15/2016. +// Copyright 2014 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 DefaultMaterials.slh@> +<@include graphics/Material.slh@> +<@include graphics/MaterialTextures.slh@> +<@include render-utils/ShaderConstants.h@> + +<@include ForwardGlobalLight.slh@> + +<$declareEvalLightmappedColor()$> + +<@include gpu/Transform.slh@> +<$declareStandardCameraTransform()$> + +<$declareMaterialTextures(ALBEDO, ROUGHNESS, NORMAL, METALLIC)$> +<$declareMaterialLightmap()$> + +layout(location=RENDER_UTILS_ATTR_POSITION_ES) in vec4 _positionES; +layout(location=RENDER_UTILS_ATTR_TEXCOORD01) in vec4 _texCoord01; +#define _texCoord0 _texCoord01.xy +#define _texCoord1 _texCoord01.zw +layout(location=RENDER_UTILS_ATTR_NORMAL_WS) in vec3 _normalWS; +layout(location=RENDER_UTILS_ATTR_TANGENT_WS) in vec3 _tangentWS; +layout(location=RENDER_UTILS_ATTR_COLOR) in vec4 _color; + +layout(location=0) out vec4 _fragColor0; + +void main(void) { + Material mat = getMaterial(); + BITFIELD matKey = getMaterialKey(mat); + <$fetchMaterialTexturesCoord0(matKey, _texCoord0, albedoTex, roughnessTex, normalTex, metallicTex)$> + <$fetchMaterialTexturesCoord1(matKey, _texCoord1, _SCRIBE_NULL, lightmap)$> + + float opacity = 1.0; + <$evalMaterialOpacity(albedoTex.a, opacity, matKey, opacity)$>; + <$discardTransparent(opacity)$>; + + vec3 albedo = getMaterialAlbedo(mat); + <$evalMaterialAlbedo(albedoTex, albedo, matKey, albedo)$>; + albedo *= _color.rgb; + + float roughness = getMaterialRoughness(mat); + <$evalMaterialRoughness(roughnessTex, roughness, matKey, roughness)$>; + + float metallic = getMaterialMetallic(mat); + <$evalMaterialMetallic(metallicTex, metallic, matKey, metallic)$>; + + vec3 fragPosition = _positionES.xyz; + vec3 fragNormal; + <$evalMaterialNormalLOD(fragPosition, normalTex, _normalWS, _tangentWS, fragNormal)$> + + TransformCamera cam = getTransformCamera(); + + vec4 color = vec4(evalLightmappedColor( + cam._viewInverse, + 1.0, + 1.0, + fragNormal, + albedo, + lightmap), + opacity); + + _fragColor0 = color; +} diff --git a/libraries/render-utils/src/render-utils/forward_model_lightmap.slp b/libraries/render-utils/src/render-utils/forward_model_lightmap.slp new file mode 100644 index 0000000000..81ac672062 --- /dev/null +++ b/libraries/render-utils/src/render-utils/forward_model_lightmap.slp @@ -0,0 +1 @@ +VERTEX model diff --git a/libraries/render-utils/src/render-utils/forward_model_normal_map_lightmap.slp b/libraries/render-utils/src/render-utils/forward_model_normal_map_lightmap.slp new file mode 100644 index 0000000000..c50be6285b --- /dev/null +++ b/libraries/render-utils/src/render-utils/forward_model_normal_map_lightmap.slp @@ -0,0 +1 @@ +VERTEX model_normal_map From 442a679108fed02716655a043ad90d4683b38d46 Mon Sep 17 00:00:00 2001 From: Anthony Thibault Date: Fri, 10 May 2019 14:12:10 -0700 Subject: [PATCH 4/8] Make DepenencyManager thread-safe again Before this PR, there were no locks around the two internal QHash data structures. Races are rare, due to the fact that the DependencyManager is initialized on the main thread on startup and the fact that a static QWeakPointer was used as an internal cache. However, there have been reported crashes where the render thread uses DependencyManager::isSet() perhaps while the main thread is adding a late dependency. DependencyManager::isSet() did not use the static QWeakPointer cache and was more prone to race conditions. To avoid this and perhaps other data races, mutexes now guard both of the internal QHash data structures. Also, as an optimization, the most frequent call to DependencyManager::isSet was removed (Profile.cpp). --- libraries/shared/src/DependencyManager.cpp | 11 +- libraries/shared/src/DependencyManager.h | 32 +-- libraries/shared/src/Profile.cpp | 4 +- tests/shared/src/DependencyManagerTests.cpp | 218 ++++++++++++++++++++ tests/shared/src/DependencyManagerTests.h | 21 ++ 5 files changed, 268 insertions(+), 18 deletions(-) create mode 100644 tests/shared/src/DependencyManagerTests.cpp create mode 100644 tests/shared/src/DependencyManagerTests.h diff --git a/libraries/shared/src/DependencyManager.cpp b/libraries/shared/src/DependencyManager.cpp index a870feab98..b8fbcad490 100644 --- a/libraries/shared/src/DependencyManager.cpp +++ b/libraries/shared/src/DependencyManager.cpp @@ -21,6 +21,13 @@ DependencyManager& DependencyManager::manager() { return *instance; } -QSharedPointer& DependencyManager::safeGet(size_t hashCode) { - return _instanceHash[hashCode]; +QSharedPointer DependencyManager::safeGet(size_t hashCode) const { + QMutexLocker lock(&_instanceHashMutex); + return _instanceHash.value(hashCode); } + +void DependencyManager::safeSet(size_t hashCode, const QSharedPointer& value) { + QMutexLocker lock(&_instanceHashMutex); + _instanceHash.insert(hashCode, value); +} + diff --git a/libraries/shared/src/DependencyManager.h b/libraries/shared/src/DependencyManager.h index bda1077990..90b0888185 100644 --- a/libraries/shared/src/DependencyManager.h +++ b/libraries/shared/src/DependencyManager.h @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -81,13 +82,17 @@ private: static DependencyManager& manager(); template - size_t getHashCode(); + size_t getHashCode() const; - QSharedPointer& safeGet(size_t hashCode); + QSharedPointer safeGet(size_t hashCode) const; + void safeSet(size_t hashCode, const QSharedPointer& value); QHash> _instanceHash; QHash _inheritanceHash; + mutable QMutex _instanceHashMutex; + mutable QMutex _inheritanceHashMutex; + bool _exiting { false }; }; @@ -121,19 +126,15 @@ template bool DependencyManager::isSet() { static size_t hashCode = manager().getHashCode(); - QSharedPointer& instance = manager().safeGet(hashCode); + QSharedPointer instance = manager().safeGet(hashCode); return !instance.isNull(); } template QSharedPointer DependencyManager::set(Args&&... args) { static size_t hashCode = manager().getHashCode(); - - QSharedPointer& instance = manager().safeGet(hashCode); - instance.clear(); // Clear instance before creation of new one to avoid edge cases QSharedPointer newInstance(new T(args...), &T::customDeleter); - QSharedPointer storedInstance = qSharedPointerCast(newInstance); - instance.swap(storedInstance); + manager().safeSet(hashCode, newInstance); return newInstance; } @@ -141,12 +142,8 @@ QSharedPointer DependencyManager::set(Args&&... args) { template QSharedPointer DependencyManager::set(Args&&... args) { static size_t hashCode = manager().getHashCode(); - - QSharedPointer& instance = manager().safeGet(hashCode); - instance.clear(); // Clear instance before creation of new one to avoid edge cases QSharedPointer newInstance(new I(args...), &I::customDeleter); - QSharedPointer storedInstance = qSharedPointerCast(newInstance); - instance.swap(storedInstance); + manager().safeSet(hashCode, newInstance); return newInstance; } @@ -154,9 +151,12 @@ QSharedPointer DependencyManager::set(Args&&... args) { template void DependencyManager::destroy() { static size_t hashCode = manager().getHashCode(); - QSharedPointer& shared = manager().safeGet(hashCode); + + QMutexLocker lock(&manager()._instanceHashMutex); + QSharedPointer shared = manager()._instanceHash.take(hashCode); QWeakPointer weak = shared; shared.clear(); + // Check that the dependency was actually destroyed. If it wasn't, it was improperly captured somewhere if (weak.lock()) { qWarning() << "DependencyManager::destroy():" << typeid(T).name() << "was not properly destroyed!"; @@ -167,12 +167,14 @@ template void DependencyManager::registerInheritance() { size_t baseHashCode = typeHash(); size_t derivedHashCode = typeHash(); + QMutexLocker lock(&manager()._inheritanceHashMutex); manager()._inheritanceHash.insert(baseHashCode, derivedHashCode); } template -size_t DependencyManager::getHashCode() { +size_t DependencyManager::getHashCode() const { size_t hashCode = typeHash(); + QMutexLocker lock(&_inheritanceHashMutex); auto derivedHashCode = _inheritanceHash.find(hashCode); while (derivedHashCode != _inheritanceHash.end()) { diff --git a/libraries/shared/src/Profile.cpp b/libraries/shared/src/Profile.cpp index 018636ad5a..1ad7b0785b 100644 --- a/libraries/shared/src/Profile.cpp +++ b/libraries/shared/src/Profile.cpp @@ -39,7 +39,9 @@ Q_LOGGING_CATEGORY(trace_baker, "trace.baker") #endif static bool tracingEnabled() { - return DependencyManager::isSet() && DependencyManager::get()->isEnabled(); + // Cheers, love! The cavalry's here! + auto tracer = DependencyManager::get(); + return (tracer && tracer->isEnabled()); } DurationBase::DurationBase(const QLoggingCategory& category, const QString& name) : _name(name), _category(category) { diff --git a/tests/shared/src/DependencyManagerTests.cpp b/tests/shared/src/DependencyManagerTests.cpp new file mode 100644 index 0000000000..6afca088a0 --- /dev/null +++ b/tests/shared/src/DependencyManagerTests.cpp @@ -0,0 +1,218 @@ + +// +// Created by Anthony Thibault on May 9th 2019 +// 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 "DependencyManagerTests.h" + +#include +#include +#include + +#include +#include + +// x macro +#define LIST_OF_CLASSES \ + CLASS(A) \ + CLASS(B) \ + CLASS(C) \ + CLASS(D) \ + CLASS(E) \ + CLASS(F) \ + CLASS(G) \ + CLASS(H) \ + CLASS(I) \ + CLASS(J) \ + CLASS(K) \ + CLASS(L) \ + CLASS(M) \ + CLASS(N) \ + CLASS(O) \ + CLASS(P) \ + CLASS(Q) \ + CLASS(R) \ + CLASS(S) \ + CLASS(T) \ + CLASS(U) \ + CLASS(V) \ + CLASS(W) \ + CLASS(X) \ + CLASS(Y) \ + CLASS(Z) \ + CLASS(AA) \ + CLASS(AB) \ + CLASS(AC) \ + CLASS(AD) \ + CLASS(AE) \ + CLASS(AF) \ + CLASS(AG) \ + CLASS(AH) \ + CLASS(AI) \ + CLASS(AJ) \ + CLASS(AK) \ + CLASS(AL) \ + CLASS(AM) \ + CLASS(AN) \ + CLASS(AO) \ + CLASS(AP) \ + CLASS(AQ) \ + CLASS(AR) \ + CLASS(AS) \ + CLASS(AT) \ + CLASS(AU) \ + CLASS(AV) \ + CLASS(AW) \ + CLASS(AX) \ + CLASS(AY) \ + CLASS(AZ) \ + CLASS(BA) \ + CLASS(BB) \ + CLASS(BC) \ + CLASS(BD) \ + CLASS(BE) \ + CLASS(BF) \ + CLASS(BG) \ + CLASS(BH) \ + CLASS(BI) \ + CLASS(BJ) \ + CLASS(BK) \ + CLASS(BL) \ + CLASS(BM) \ + CLASS(BN) \ + CLASS(BO) \ + CLASS(BP) \ + CLASS(BQ) \ + CLASS(BR) \ + CLASS(BS) \ + CLASS(BT) \ + CLASS(BU) \ + CLASS(BV) \ + CLASS(BW) \ + CLASS(BX) \ + CLASS(BY) \ + CLASS(BZ) \ + CLASS(CA) \ + CLASS(CB) \ + CLASS(CC) \ + CLASS(CD) \ + CLASS(CE) \ + CLASS(CF) \ + CLASS(CG) \ + CLASS(CH) \ + CLASS(CI) \ + CLASS(CJ) \ + CLASS(CK) \ + CLASS(CL) \ + CLASS(CM) \ + CLASS(CN) \ + CLASS(CO) \ + CLASS(CP) \ + CLASS(CQ) \ + CLASS(CR) \ + CLASS(CS) \ + CLASS(CT) \ + CLASS(CU) \ + CLASS(CV) \ + CLASS(CW) \ + CLASS(CX) \ + CLASS(CY) \ + CLASS(CZ) \ + CLASS(DA) \ + CLASS(DB) \ + CLASS(DC) \ + CLASS(DD) \ + CLASS(DE) \ + CLASS(DF) \ + CLASS(DG) \ + CLASS(DH) \ + CLASS(DI) \ + CLASS(DJ) \ + CLASS(DK) \ + CLASS(DL) \ + CLASS(DM) \ + CLASS(DN) \ + CLASS(DO) \ + CLASS(DP) \ + CLASS(DQ) \ + CLASS(DR) \ + CLASS(DS) \ + CLASS(DT) \ + CLASS(DU) \ + CLASS(DV) \ + CLASS(DW) \ + CLASS(DX) \ + CLASS(DY) \ + CLASS(DZ) + + +QTEST_MAIN(DependencyManagerTests) + +#define CLASS(NAME) class NAME : public Dependency {}; +LIST_OF_CLASSES +#undef CLASS + +void DependencyManagerTests::testDependencyManager() { + QCOMPARE(DependencyManager::isSet(), false); + DependencyManager::set(); + QCOMPARE(DependencyManager::isSet(), true); + DependencyManager::destroy(); + QCOMPARE(DependencyManager::isSet(), false); +} + +static void addDeps() { + +#define CLASS(NAME) DependencyManager::set(); +LIST_OF_CLASSES +#undef CLASS +} + +static void removeDeps() { +#define CLASS(NAME) DependencyManager::destroy(); +LIST_OF_CLASSES +#undef CLASS +} + + +static void spamIsSet() { + for (int i = 0; i < 1000; i++) { +#define CLASS(NAME) DependencyManager::isSet(); +LIST_OF_CLASSES +#undef CLASS + } +} + +static void spamGet() { + for (int i = 0; i < 10; i++) { +#define CLASS(NAME) DependencyManager::get(); +LIST_OF_CLASSES +#undef CLASS + } +} + + +void assertDeps(bool value) { +#define CLASS(NAME) QCOMPARE(DependencyManager::isSet(), value); +LIST_OF_CLASSES +#undef CLASS +} + +void DependencyManagerTests::testDependencyManagerMultiThreaded() { + + std::thread isSetThread1(spamIsSet); // spawn new thread that checks of dpendencies are present by calling isSet() + std::thread getThread1(spamGet); // spawn new thread that checks of dpendencies are present by calling get() + addDeps(); + isSetThread1.join(); + getThread1.join(); + assertDeps(true); + + std::thread isSetThread2(spamIsSet); // spawn new thread that checks of dpendencies are present by calling isSet() + std::thread getThread2(spamGet); // spawn new thread that checks of dpendencies are present by calling get() + removeDeps(); + isSetThread2.join(); + getThread2.join(); + assertDeps(false); +} diff --git a/tests/shared/src/DependencyManagerTests.h b/tests/shared/src/DependencyManagerTests.h new file mode 100644 index 0000000000..d497eda8bf --- /dev/null +++ b/tests/shared/src/DependencyManagerTests.h @@ -0,0 +1,21 @@ +// +// Created by Anthony Thibault on May 9th 2019 +// 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_DependencyManagerTests_h +#define hifi_DependencyManagerTests_h + +#include + +class DependencyManagerTests : public QObject { + Q_OBJECT +private slots: + void testDependencyManager(); + void testDependencyManagerMultiThreaded(); +}; + +#endif // hifi_DependencyManagerTests_h From dfdace8cdc049714895bae5bea55b07a2cdaf956 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Fri, 10 May 2019 14:52:26 -0700 Subject: [PATCH 5/8] fix zones for real this time --- .../src/EntityTreeRenderer.cpp | 72 ++++++++++--------- .../src/EntityTreeRenderer.h | 14 ++-- 2 files changed, 46 insertions(+), 40 deletions(-) diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index fbf577755d..ae8473e544 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -591,7 +591,7 @@ void EntityTreeRenderer::findBestZoneAndMaybeContainingEntities(QSetgetVisible() && renderableIdForEntity(entity) != render::Item::INVALID_ITEM_ID) { - _layeredZones.emplace(std::dynamic_pointer_cast(entity)); + _layeredZones.emplace_back(std::dynamic_pointer_cast(entity)); } if ((!hasScript && isZone) || scriptHasLoaded) { @@ -600,6 +600,7 @@ void EntityTreeRenderer::findBestZoneAndMaybeContainingEntities(QSet(getTree()->findEntityByEntityItemID(id))) { - _layeredZones.update(zone, _avatarPosition, this); - applyLayeredZones(); + if (_layeredZones.update(zone, _avatarPosition, this)) { + applyLayeredZones(); + } } } bool EntityTreeRenderer::LayeredZones::clearDomainAndNonOwnedZones(const QUuid& sessionUUID) { bool zonesChanged = false; - auto it = c.begin(); - while (it != c.end()) { + auto it = begin(); + while (it != end()) { auto zone = it->zone.lock(); if (!zone || !(zone->isLocalEntity() || (zone->isAvatarEntity() && zone->getOwningAvatarID() == sessionUUID))) { zonesChanged = true; - it = c.erase(it); + it = erase(it); } else { it++; } } if (zonesChanged) { - std::make_heap(c.begin(), c.end(), comp); + sort(); } return zonesChanged; } std::pair EntityTreeRenderer::LayeredZones::getZoneInteractionProperties() const { - auto it = c.cbegin(); - while (it != c.cend()) { + for (auto it = cbegin(); it != cend(); it++) { auto zone = it->zone.lock(); if (zone && zone->isDomainEntity()) { return { zone->getFlyingAllowed(), zone->getGhostingAllowed() }; } - it++; } return { true, true }; } -void EntityTreeRenderer::LayeredZones::remove(const std::shared_ptr& zone) { - auto it = c.begin(); - while (it != c.end()) { - if (it->zone.lock() == zone) { - break; - } - it++; - } - if (it != c.end()) { - c.erase(it); - std::make_heap(c.begin(), c.end(), comp); - } -} - -void EntityTreeRenderer::LayeredZones::update(std::shared_ptr zone, const glm::vec3& position, EntityTreeRenderer* entityTreeRenderer) { +bool EntityTreeRenderer::LayeredZones::update(std::shared_ptr zone, const glm::vec3& position, EntityTreeRenderer* entityTreeRenderer) { // When a zone's position or visibility changes, we call this method // In order to resort our zones, we first remove the changed zone, and then re-insert it if necessary - remove(zone); + + bool needsResort = false; + + { + auto it = begin(); + while (it != end()) { + if (it->zone.lock() == zone) { + break; + } + it++; + } + if (it != end()) { + erase(it); + needsResort = true; + } + } // Only call contains if the zone is rendering if (zone->isVisible() && entityTreeRenderer->renderableIdForEntity(zone) != render::Item::INVALID_ITEM_ID && zone->contains(position)) { - emplace(zone); + emplace_back(zone); + needsResort = true; } + + if (needsResort) { + sort(); + } + + return needsResort; } bool EntityTreeRenderer::LayeredZones::equals(const LayeredZones& other) const { @@ -1254,9 +1262,9 @@ bool EntityTreeRenderer::LayeredZones::equals(const LayeredZones& other) const { return false; } - auto it = c.cbegin(); - auto otherIt = other.c.cbegin(); - while (it != c.cend()) { + auto it = cbegin(); + auto otherIt = other.cbegin(); + while (it != cend()) { if (*it != *otherIt) { return false; } @@ -1268,15 +1276,13 @@ bool EntityTreeRenderer::LayeredZones::equals(const LayeredZones& other) const { } void EntityTreeRenderer::LayeredZones::appendRenderIDs(render::ItemIDs& list, EntityTreeRenderer* entityTreeRenderer) const { - auto it = c.cbegin(); - while (it != c.cend()) { + for (auto it = cbegin(); it != cend(); it++) { if (it->zone.lock()) { auto id = entityTreeRenderer->renderableIdForEntityId(it->id); if (id != render::Item::INVALID_ITEM_ID) { list.push_back(id); } } - it++; } } diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.h b/libraries/entities-renderer/src/EntityTreeRenderer.h index a0243a159a..f794d947ed 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.h +++ b/libraries/entities-renderer/src/EntityTreeRenderer.h @@ -213,24 +213,24 @@ private: public: LayeredZone(std::shared_ptr zone) : zone(zone), id(zone->getID()), volume(zone->getVolumeEstimate()) {} - bool operator>(const LayeredZone& r) const { return volume > r.volume; } - bool operator==(const LayeredZone& r) const { return zone.lock() == r.zone.lock(); } + // We need to sort on volume AND id so that different clients sort zones with identical volumes the same way + bool operator<(const LayeredZone& r) const { return volume < r.volume || (volume == r.volume && id < r.id); } + bool operator==(const LayeredZone& r) const { return zone.lock() && zone.lock() == r.zone.lock(); } bool operator!=(const LayeredZone& r) const { return !(*this == r); } - bool operator>=(const LayeredZone& r) const { return (*this > r) || (*this == r); } + bool operator<=(const LayeredZone& r) const { return (*this < r) || (*this == r); } std::weak_ptr zone; QUuid id; float volume; }; - class LayeredZones : public std::priority_queue, std::greater> { + class LayeredZones : public std::vector { public: - void clear() { *this = LayeredZones(); } bool clearDomainAndNonOwnedZones(const QUuid& sessionUUID); + void sort() { std::sort(begin(), end(), std::less()); } bool equals(const LayeredZones& other) const; - void remove(const std::shared_ptr& zone); - void update(std::shared_ptr zone, const glm::vec3& position, EntityTreeRenderer* entityTreeRenderer); + bool update(std::shared_ptr zone, const glm::vec3& position, EntityTreeRenderer* entityTreeRenderer); void appendRenderIDs(render::ItemIDs& list, EntityTreeRenderer* entityTreeRenderer) const; std::pair getZoneInteractionProperties() const; From fe17550a80486b901582780b54a3b202c2f6cd2a Mon Sep 17 00:00:00 2001 From: Anthony Thibault Date: Fri, 10 May 2019 15:41:52 -0700 Subject: [PATCH 6/8] Code review feedback In DependencyManager::set<>() destroy the clear the previous before allocating the new instance. --- libraries/shared/src/DependencyManager.cpp | 5 ----- libraries/shared/src/DependencyManager.h | 21 ++++++++++++++++++--- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/libraries/shared/src/DependencyManager.cpp b/libraries/shared/src/DependencyManager.cpp index b8fbcad490..e56dd0df88 100644 --- a/libraries/shared/src/DependencyManager.cpp +++ b/libraries/shared/src/DependencyManager.cpp @@ -26,8 +26,3 @@ QSharedPointer DependencyManager::safeGet(size_t hashCode) const { return _instanceHash.value(hashCode); } -void DependencyManager::safeSet(size_t hashCode, const QSharedPointer& value) { - QMutexLocker lock(&_instanceHashMutex); - _instanceHash.insert(hashCode, value); -} - diff --git a/libraries/shared/src/DependencyManager.h b/libraries/shared/src/DependencyManager.h index 90b0888185..e188c8e9a4 100644 --- a/libraries/shared/src/DependencyManager.h +++ b/libraries/shared/src/DependencyManager.h @@ -85,7 +85,6 @@ private: size_t getHashCode() const; QSharedPointer safeGet(size_t hashCode) const; - void safeSet(size_t hashCode, const QSharedPointer& value); QHash> _instanceHash; QHash _inheritanceHash; @@ -133,8 +132,16 @@ bool DependencyManager::isSet() { template QSharedPointer DependencyManager::set(Args&&... args) { static size_t hashCode = manager().getHashCode(); + QMutexLocker lock(&manager()._instanceHashMutex); + + // clear the previous instance before constructing the new instance + auto iter = manager()._instanceHash.find(hashCode); + if (iter != manager()._instanceHash.end()) { + iter.value().clear(); + } + QSharedPointer newInstance(new T(args...), &T::customDeleter); - manager().safeSet(hashCode, newInstance); + manager()._instanceHash.insert(hashCode, newInstance); return newInstance; } @@ -142,8 +149,16 @@ QSharedPointer DependencyManager::set(Args&&... args) { template QSharedPointer DependencyManager::set(Args&&... args) { static size_t hashCode = manager().getHashCode(); + QMutexLocker lock(&manager()._instanceHashMutex); + + // clear the previous instance before constructing the new instance + auto iter = manager()._instanceHash.find(hashCode); + if (iter != manager()._instanceHash.end()) { + iter.value().clear(); + } + QSharedPointer newInstance(new I(args...), &I::customDeleter); - manager().safeSet(hashCode, newInstance); + _instanceHash.insert(hashCode, newInstance); return newInstance; } From b46378e0b67801ba5a25b283f14c3ac6ba46a3cd Mon Sep 17 00:00:00 2001 From: Anthony Thibault Date: Fri, 10 May 2019 15:51:42 -0700 Subject: [PATCH 7/8] Compile error fix --- libraries/shared/src/DependencyManager.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/shared/src/DependencyManager.h b/libraries/shared/src/DependencyManager.h index e188c8e9a4..8eddb572cf 100644 --- a/libraries/shared/src/DependencyManager.h +++ b/libraries/shared/src/DependencyManager.h @@ -158,7 +158,7 @@ QSharedPointer DependencyManager::set(Args&&... args) { } QSharedPointer newInstance(new I(args...), &I::customDeleter); - _instanceHash.insert(hashCode, newInstance); + manager()._instanceHash.insert(hashCode, newInstance); return newInstance; } From eb8c7220801d541bd2e38573d1e053232827712a Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Thu, 9 May 2019 14:11:29 -0700 Subject: [PATCH 8/8] fix runtime switch --- interface/src/Application.cpp | 2 +- interface/src/graphics/WorldBox.cpp | 2 +- interface/src/raypick/ParabolaPointer.cpp | 46 ++++----- interface/src/raypick/ParabolaPointer.h | 5 +- .../src/workload/GameWorkloadRenderer.cpp | 2 + .../src/avatars-renderer/Avatar.cpp | 12 +-- .../src/avatars-renderer/Avatar.h | 2 +- .../src/RenderableGizmoEntityItem.cpp | 4 +- .../src/RenderableGridEntityItem.cpp | 4 +- .../src/RenderableLineEntityItem.cpp | 3 +- .../src/RenderableModelEntityItem.cpp | 2 +- .../src/RenderablePolyLineEntityItem.cpp | 38 +++----- .../src/RenderablePolyLineEntityItem.h | 5 +- .../src/RenderableShapeEntityItem.cpp | 2 +- .../src/RenderableTextEntityItem.cpp | 10 +- .../procedural/src/procedural/Procedural.cpp | 1 + libraries/render-utils/src/GeometryCache.cpp | 94 +++++++++---------- libraries/render-utils/src/GeometryCache.h | 16 ++-- libraries/render-utils/src/Model.cpp | 4 +- libraries/render-utils/src/Model.h | 2 +- libraries/render-utils/src/RenderCommonTask.h | 12 +++ .../render-utils/src/RenderForwardTask.cpp | 2 + libraries/render-utils/src/RenderViewTask.cpp | 15 +-- libraries/render-utils/src/TextRenderer3D.cpp | 4 +- libraries/render-utils/src/TextRenderer3D.h | 4 +- libraries/render-utils/src/forward_grid.slf | 40 ++++++++ .../src/forward_grid_translucent.slf | 41 ++++++++ .../render-utils/src/forward_parabola.slf | 18 ++++ .../render-utils/src/parabola_forward.slv | 7 -- .../src/render-utils/forward_grid.slp | 1 + .../render-utils/forward_grid_translucent.slp | 1 + .../src/render-utils/forward_parabola.slp | 1 + libraries/render-utils/src/text/Font.cpp | 36 +++---- libraries/render-utils/src/text/Font.h | 14 ++- libraries/render/src/render/Args.h | 4 + libraries/shared/src/DisableDeferred.h | 24 ----- libraries/shared/src/RenderForward.h | 24 +++++ libraries/task/src/task/Task.h | 10 +- 38 files changed, 303 insertions(+), 211 deletions(-) create mode 100644 libraries/render-utils/src/forward_grid.slf create mode 100644 libraries/render-utils/src/forward_grid_translucent.slf create mode 100644 libraries/render-utils/src/forward_parabola.slf delete mode 100644 libraries/render-utils/src/parabola_forward.slv create mode 100644 libraries/render-utils/src/render-utils/forward_grid.slp create mode 100644 libraries/render-utils/src/render-utils/forward_grid_translucent.slp create mode 100644 libraries/render-utils/src/render-utils/forward_parabola.slp delete mode 100644 libraries/shared/src/DisableDeferred.h create mode 100644 libraries/shared/src/RenderForward.h diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 6430792dc4..941b8543a5 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -6722,7 +6722,7 @@ void Application::updateRenderArgs(float deltaTime) { } appRenderArgs._renderArgs = RenderArgs(_graphicsEngine.getGPUContext(), lodManager->getOctreeSizeScale(), lodManager->getBoundaryLevelAdjust(), lodManager->getLODAngleHalfTan(), RenderArgs::DEFAULT_RENDER_MODE, - RenderArgs::MONO, RenderArgs::RENDER_DEBUG_NONE); + RenderArgs::MONO, RenderArgs::DEFERRED, RenderArgs::RENDER_DEBUG_NONE); appRenderArgs._renderArgs._scene = getMain3DScene(); { diff --git a/interface/src/graphics/WorldBox.cpp b/interface/src/graphics/WorldBox.cpp index 908055e9c6..a28850207f 100644 --- a/interface/src/graphics/WorldBox.cpp +++ b/interface/src/graphics/WorldBox.cpp @@ -22,7 +22,7 @@ namespace render { PerformanceTimer perfTimer("worldBox"); auto& batch = *args->_batch; - DependencyManager::get()->bindSimpleProgram(batch); + DependencyManager::get()->bindSimpleProgram(batch, false, false, true, false, false, true, args->_renderMethod == Args::RenderMethod::FORWARD); WorldBoxRenderData::renderWorldBox(args, batch); } } diff --git a/interface/src/raypick/ParabolaPointer.cpp b/interface/src/raypick/ParabolaPointer.cpp index 389f6ed286..23fc1cb4bd 100644 --- a/interface/src/raypick/ParabolaPointer.cpp +++ b/interface/src/raypick/ParabolaPointer.cpp @@ -20,8 +20,7 @@ const float ParabolaPointer::RenderState::ParabolaRenderItem::DEFAULT_PARABOLA_W const bool ParabolaPointer::RenderState::ParabolaRenderItem::DEFAULT_PARABOLA_ISVISIBLEINSECONDARYCAMERA { false }; const bool ParabolaPointer::RenderState::ParabolaRenderItem::DEFAULT_PARABOLA_DRAWINFRONT { false }; -gpu::PipelinePointer ParabolaPointer::RenderState::ParabolaRenderItem::_parabolaPipeline { nullptr }; -gpu::PipelinePointer ParabolaPointer::RenderState::ParabolaRenderItem::_transparentParabolaPipeline { nullptr }; +std::map, gpu::PipelinePointer> ParabolaPointer::RenderState::ParabolaRenderItem::_parabolaPipelines; ParabolaPointer::ParabolaPointer(const QVariant& rayProps, const RenderStateMap& renderStates, const DefaultRenderStateMap& defaultRenderStates, bool hover, const PointerTriggers& triggers, bool faceAvatar, bool followNormal, float followNormalStrength, bool centerEndY, bool lockEnd, bool distanceScaleEnd, @@ -401,33 +400,34 @@ void ParabolaPointer::RenderState::ParabolaRenderItem::updateBounds() { _bound = AABox(min, max - min); } -const gpu::PipelinePointer ParabolaPointer::RenderState::ParabolaRenderItem::getParabolaPipeline() { - if (!_parabolaPipeline || !_transparentParabolaPipeline) { - { - gpu::ShaderPointer program = gpu::Shader::createProgram(shader::render_utils::program::parabola); - auto state = std::make_shared(); +gpu::PipelinePointer ParabolaPointer::RenderState::ParabolaRenderItem::getParabolaPipeline(bool forward) const { + if (_parabolaPipelines.empty()) { + using namespace shader::render_utils::program; + + static const std::vector> keys = { + std::make_tuple(false, false, parabola), std::make_tuple(false, true, forward_parabola), std::make_tuple(true, false, parabola_translucent)/*, std::make_tuple(true, true, forward_parabola_translucent)*/ + }; + + for (auto& key : keys) { + gpu::StatePointer state = gpu::StatePointer(new gpu::State()); state->setDepthTest(true, true, gpu::LESS_EQUAL); - state->setBlendFunction(false, + if (std::get<0>(key)) { + PrepareStencil::testMask(*state); + } else { + PrepareStencil::testMaskDrawShape(*state); + } + state->setBlendFunction(std::get<0>(key), gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); - PrepareStencil::testMaskDrawShape(*state); state->setCullMode(gpu::State::CULL_NONE); - _parabolaPipeline = gpu::Pipeline::create(program, state); + + _parabolaPipelines[{std::get<0>(key), std::get<1>(key)}] = gpu::Pipeline::create(gpu::Shader::createProgram(std::get<2>(key)), state); } - { - gpu::ShaderPointer program = gpu::Shader::createProgram(shader::render_utils::program::parabola_translucent); - auto state = std::make_shared(); - state->setDepthTest(true, true, gpu::LESS_EQUAL); - state->setBlendFunction(true, - gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, - gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); - PrepareStencil::testMask(*state); - state->setCullMode(gpu::State::CULL_NONE); - _transparentParabolaPipeline = gpu::Pipeline::create(program, state); - } + // The forward opaque/translucent pipelines are the same for now + _parabolaPipelines[{ true, true }] = _parabolaPipelines[{ false, true}]; } - return (_parabolaData.color.a < 1.0f ? _transparentParabolaPipeline : _parabolaPipeline); + return _parabolaPipelines[{ _parabolaData.color.a < 1.0f, forward }]; } void ParabolaPointer::RenderState::ParabolaRenderItem::render(RenderArgs* args) { @@ -441,7 +441,7 @@ void ParabolaPointer::RenderState::ParabolaRenderItem::render(RenderArgs* args) transform.setTranslation(_origin); batch.setModelTransform(transform); - batch.setPipeline(getParabolaPipeline()); + batch.setPipeline(getParabolaPipeline(args->_renderMethod == render::Args::RenderMethod::FORWARD)); const int MAX_SECTIONS = 100; if (glm::length2(_parabolaData.acceleration) < EPSILON) { diff --git a/interface/src/raypick/ParabolaPointer.h b/interface/src/raypick/ParabolaPointer.h index d4b705a7d2..94470971e6 100644 --- a/interface/src/raypick/ParabolaPointer.h +++ b/interface/src/raypick/ParabolaPointer.h @@ -26,9 +26,8 @@ public: bool isVisibleInSecondaryCamera, bool drawInFront, bool enabled); ~ParabolaRenderItem() {} - static gpu::PipelinePointer _parabolaPipeline; - static gpu::PipelinePointer _transparentParabolaPipeline; - const gpu::PipelinePointer getParabolaPipeline(); + static std::map, gpu::PipelinePointer> _parabolaPipelines; + gpu::PipelinePointer getParabolaPipeline(bool forward) const; void render(RenderArgs* args); render::Item::Bound& editBound() { return _bound; } diff --git a/interface/src/workload/GameWorkloadRenderer.cpp b/interface/src/workload/GameWorkloadRenderer.cpp index a2fb32d396..2bb73999f1 100644 --- a/interface/src/workload/GameWorkloadRenderer.cpp +++ b/interface/src/workload/GameWorkloadRenderer.cpp @@ -145,6 +145,7 @@ void GameWorkloadRenderItem::setAllViews(const workload::Views& views) { } const gpu::PipelinePointer GameWorkloadRenderItem::getProxiesPipeline() { + // FIXME: this needs a forward pipeline, or to only write to one output if (!_drawAllProxiesPipeline) { gpu::ShaderPointer program = gpu::Shader::createProgram(shader::render_utils::program::drawWorkloadProxy); auto state = std::make_shared(); @@ -162,6 +163,7 @@ const gpu::PipelinePointer GameWorkloadRenderItem::getProxiesPipeline() { const gpu::PipelinePointer GameWorkloadRenderItem::getViewsPipeline() { + // FIXME: this needs a forward pipeline, or to only write to one output if (!_drawAllViewsPipeline) { gpu::ShaderPointer program = gpu::Shader::createProgram(shader::render_utils::program::drawWorkloadView); auto state = std::make_shared(); diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp index cb0acd68cb..4a106d0f36 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp @@ -779,7 +779,7 @@ void Avatar::render(RenderArgs* renderArgs) { pointerTransform.setTranslation(position); pointerTransform.setRotation(rotation); batch.setModelTransform(pointerTransform); - geometryCache->bindSimpleProgram(batch); + geometryCache->bindSimpleProgram(batch, false, false, true, false, false, true, renderArgs->_renderMethod == render::Args::FORWARD); geometryCache->renderLine(batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, laserLength, 0.0f), laserColor, _leftPointerGeometryID); } } @@ -803,7 +803,7 @@ void Avatar::render(RenderArgs* renderArgs) { pointerTransform.setTranslation(position); pointerTransform.setRotation(rotation); batch.setModelTransform(pointerTransform); - geometryCache->bindSimpleProgram(batch); + geometryCache->bindSimpleProgram(batch, false, false, true, false, false, true, renderArgs->_renderMethod == render::Args::FORWARD); geometryCache->renderLine(batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, laserLength, 0.0f), laserColor, _rightPointerGeometryID); } } @@ -829,7 +829,7 @@ void Avatar::render(RenderArgs* renderArgs) { auto& frustum = renderArgs->getViewFrustum(); auto textPosition = getDisplayNamePosition(); if (frustum.pointIntersectsFrustum(textPosition)) { - renderDisplayName(batch, frustum, textPosition); + renderDisplayName(batch, frustum, textPosition, renderArgs->_renderMethod == render::Args::FORWARD); } } } @@ -1034,7 +1034,7 @@ Transform Avatar::calculateDisplayNameTransform(const ViewFrustum& view, const g return result; } -void Avatar::renderDisplayName(gpu::Batch& batch, const ViewFrustum& view, const glm::vec3& textPosition) const { +void Avatar::renderDisplayName(gpu::Batch& batch, const ViewFrustum& view, const glm::vec3& textPosition, bool forward) const { PROFILE_RANGE_BATCH(batch, __FUNCTION__); bool shouldShowReceiveStats = showReceiveStats && !isMyAvatar(); @@ -1090,7 +1090,7 @@ void Avatar::renderDisplayName(gpu::Batch& batch, const ViewFrustum& view, const { PROFILE_RANGE_BATCH(batch, __FUNCTION__":renderBevelCornersRect"); - DependencyManager::get()->bindSimpleProgram(batch, false, false, true, true, true); + DependencyManager::get()->bindSimpleProgram(batch, false, false, true, true, true, true, forward); DependencyManager::get()->renderBevelCornersRect(batch, left, bottom, width, height, bevelDistance, backgroundColor, _nameRectGeometryID); } @@ -1103,7 +1103,7 @@ void Avatar::renderDisplayName(gpu::Batch& batch, const ViewFrustum& view, const batch.setModelTransform(textTransform); { PROFILE_RANGE_BATCH(batch, __FUNCTION__":renderText"); - renderer->draw(batch, text_x, -text_y, nameUTF8.data(), textColor); + renderer->draw(batch, text_x, -text_y, nameUTF8.data(), textColor, glm::vec2(-1.0f), forward); } } } diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.h b/libraries/avatars-renderer/src/avatars-renderer/Avatar.h index a196c018d2..53f13ef191 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.h +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.h @@ -694,7 +694,7 @@ protected: glm::vec3 getDisplayNamePosition() const; Transform calculateDisplayNameTransform(const ViewFrustum& view, const glm::vec3& textPosition) const; - void renderDisplayName(gpu::Batch& batch, const ViewFrustum& view, const glm::vec3& textPosition) const; + void renderDisplayName(gpu::Batch& batch, const ViewFrustum& view, const glm::vec3& textPosition, bool forward) const; virtual bool shouldRenderHead(const RenderArgs* renderArgs) const; virtual void fixupModelsInScene(const render::ScenePointer& scene); diff --git a/libraries/entities-renderer/src/RenderableGizmoEntityItem.cpp b/libraries/entities-renderer/src/RenderableGizmoEntityItem.cpp index 1a188ca163..9468fdf3ef 100644 --- a/libraries/entities-renderer/src/RenderableGizmoEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableGizmoEntityItem.cpp @@ -261,15 +261,17 @@ void GizmoEntityRenderer::doRender(RenderArgs* args) { Transform transform; bool hasTickMarks; glm::vec4 tickProperties; + bool forward; withReadLock([&] { transform = _renderTransform; hasTickMarks = _ringProperties.getHasTickMarks(); tickProperties = glm::vec4(_ringProperties.getMajorTickMarksAngle(), _ringProperties.getMajorTickMarksLength(), _ringProperties.getMinorTickMarksAngle(), _ringProperties.getMinorTickMarksLength()); + forward = _renderLayer != RenderLayer::WORLD || args->_renderMethod == Args::RenderMethod::FORWARD; }); bool wireframe = render::ShapeKey(args->_globalShapeKey).isWireframe() || _primitiveMode == PrimitiveMode::LINES; - geometryCache->bindSimpleProgram(batch, false, isTransparent(), false, wireframe, true, true, _renderLayer != RenderLayer::WORLD); + geometryCache->bindSimpleProgram(batch, false, isTransparent(), false, wireframe, true, true, forward); batch.setModelTransform(transform); diff --git a/libraries/entities-renderer/src/RenderableGridEntityItem.cpp b/libraries/entities-renderer/src/RenderableGridEntityItem.cpp index f05ba35c79..31969e36fc 100644 --- a/libraries/entities-renderer/src/RenderableGridEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableGridEntityItem.cpp @@ -113,11 +113,13 @@ void GridEntityRenderer::doRender(RenderArgs* args) { glm::vec4 color; glm::vec3 dimensions; Transform renderTransform; + bool forward; withReadLock([&] { color = glm::vec4(toGlm(_color), _alpha); color = EntityRenderer::calculatePulseColor(color, _pulseProperties, _created); dimensions = _dimensions; renderTransform = _renderTransform; + forward = _renderLayer != RenderLayer::WORLD || args->_renderMethod == Args::RenderMethod::FORWARD; }); if (!_visible) { @@ -153,5 +155,5 @@ void GridEntityRenderer::doRender(RenderArgs* args) { DependencyManager::get()->renderGrid(*batch, minCorner, maxCorner, minorGridRowDivisions, minorGridColDivisions, MINOR_GRID_EDGE, majorGridRowDivisions, majorGridColDivisions, MAJOR_GRID_EDGE, - color, _geometryId); + color, forward, _geometryId); } \ No newline at end of file diff --git a/libraries/entities-renderer/src/RenderableLineEntityItem.cpp b/libraries/entities-renderer/src/RenderableLineEntityItem.cpp index 9c5424950a..cbe2a98166 100644 --- a/libraries/entities-renderer/src/RenderableLineEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableLineEntityItem.cpp @@ -55,7 +55,8 @@ void LineEntityRenderer::doRender(RenderArgs* args) { transform.setRotation(modelTransform.getRotation()); batch.setModelTransform(transform); if (_linePoints.size() > 1) { - DependencyManager::get()->bindSimpleProgram(batch); + DependencyManager::get()->bindSimpleProgram(batch, false, false, true, false, false, true, + _renderLayer != RenderLayer::WORLD || args->_renderMethod == Args::RenderMethod::FORWARD); DependencyManager::get()->renderVertices(batch, gpu::LINE_STRIP, _lineVerticesID); } } diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index bfbbe12ea6..df5b1d91f0 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -1520,7 +1520,7 @@ void ModelEntityRenderer::doRender(RenderArgs* args) { model = _model; }); if (model) { - model->renderDebugMeshBoxes(batch); + model->renderDebugMeshBoxes(batch, args->_renderMethod == Args::RenderMethod::FORWARD); } #endif } diff --git a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp index 2430643ce2..d7246f9ba5 100644 --- a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp @@ -19,15 +19,12 @@ #include #include -#include - #include "paintStroke_Shared.slh" using namespace render; using namespace render::entities; -gpu::PipelinePointer PolyLineEntityRenderer::_pipeline = nullptr; -gpu::PipelinePointer PolyLineEntityRenderer::_glowPipeline = nullptr; +std::map, gpu::PipelinePointer> PolyLineEntityRenderer::_pipelines; static const QUrl DEFAULT_POLYLINE_TEXTURE = PathUtils::resourcesUrl("images/paintStroke.png"); @@ -44,29 +41,24 @@ PolyLineEntityRenderer::PolyLineEntityRenderer(const EntityItemPointer& entity) } } -void PolyLineEntityRenderer::buildPipeline() { - // FIXME: opaque pipeline - gpu::ShaderPointer program = gpu::Shader::createProgram(DISABLE_DEFERRED ? shader::entities_renderer::program::paintStroke_forward : shader::entities_renderer::program::paintStroke); +void PolyLineEntityRenderer::buildPipelines() { + // FIXME: opaque pipelines + + static const std::vector> keys = { + { render::Args::DEFERRED, false }, { render::Args::DEFERRED, true }, { render::Args::FORWARD, false }, { render::Args::FORWARD, true }, + }; + + for (auto& key : keys) { + gpu::ShaderPointer program = gpu::Shader::createProgram(key.first == render::Args::DEFERRED ? shader::entities_renderer::program::paintStroke : shader::entities_renderer::program::paintStroke_forward); - { gpu::StatePointer state = gpu::StatePointer(new gpu::State()); state->setCullMode(gpu::State::CullMode::CULL_NONE); - state->setDepthTest(true, true, gpu::LESS_EQUAL); + state->setDepthTest(true, !key.second, gpu::LESS_EQUAL); PrepareStencil::testMask(*state); state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); - _pipeline = gpu::Pipeline::create(program, state); - } - { - gpu::StatePointer state = gpu::StatePointer(new gpu::State()); - state->setCullMode(gpu::State::CullMode::CULL_NONE); - state->setDepthTest(true, false, gpu::LESS_EQUAL); - PrepareStencil::testMask(*state); - state->setBlendFunction(true, - gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, - gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); - _glowPipeline = gpu::Pipeline::create(program, state); + _pipelines[key] = gpu::Pipeline::create(program, state); } } @@ -299,11 +291,11 @@ void PolyLineEntityRenderer::doRender(RenderArgs* args) { return; } - if (!_pipeline) { - buildPipeline(); + if (_pipelines.empty()) { + buildPipelines(); } - batch.setPipeline(_glow ? _glowPipeline : _pipeline); + batch.setPipeline(_pipelines[{args->_renderMethod, _glow}]); batch.setModelTransform(transform); batch.setResourceTexture(0, texture); batch.draw(gpu::TRIANGLE_STRIP, (gpu::uint32)(2 * numVertices), 0); diff --git a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.h b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.h index 3815b57671..adb30362da 100644 --- a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.h +++ b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.h @@ -37,7 +37,7 @@ protected: virtual ShapeKey getShapeKey() override; virtual void doRender(RenderArgs* args) override; - void buildPipeline(); + static void buildPipelines(); void updateGeometry(); void updateData(); @@ -58,8 +58,7 @@ protected: size_t _numVertices; gpu::BufferPointer _polylineDataBuffer; gpu::BufferPointer _polylineGeometryBuffer; - static gpu::PipelinePointer _pipeline; - static gpu::PipelinePointer _glowPipeline; + static std::map, gpu::PipelinePointer> _pipelines; }; } } // namespace diff --git a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp index 2548ae5914..6a0d7b001c 100644 --- a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp @@ -280,7 +280,7 @@ void ShapeEntityRenderer::doRender(RenderArgs* args) { // FIXME, support instanced multi-shape rendering using multidraw indirect outColor.a *= _isFading ? Interpolate::calculateFadeRatio(_fadeStartTime) : 1.0f; render::ShapePipelinePointer pipeline; - if (renderLayer == RenderLayer::WORLD) { + if (renderLayer == RenderLayer::WORLD && args->_renderMethod != Args::RenderMethod::FORWARD) { pipeline = outColor.a < 1.0f ? geometryCache->getTransparentShapePipeline() : geometryCache->getOpaqueShapePipeline(); } else { pipeline = outColor.a < 1.0f ? geometryCache->getForwardTransparentShapePipeline() : geometryCache->getForwardOpaqueShapePipeline(); diff --git a/libraries/entities-renderer/src/RenderableTextEntityItem.cpp b/libraries/entities-renderer/src/RenderableTextEntityItem.cpp index 81f367a956..a281c1d097 100644 --- a/libraries/entities-renderer/src/RenderableTextEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableTextEntityItem.cpp @@ -163,7 +163,7 @@ void TextEntityRenderer::doRender(RenderArgs* args) { Transform modelTransform; glm::vec3 dimensions; BillboardMode billboardMode; - bool layered; + bool forward; withReadLock([&] { modelTransform = _renderTransform; dimensions = _dimensions; @@ -174,7 +174,7 @@ void TextEntityRenderer::doRender(RenderArgs* args) { textColor = EntityRenderer::calculatePulseColor(textColor, _pulseProperties, _created); backgroundColor = glm::vec4(_backgroundColor, fadeRatio * _backgroundAlpha); backgroundColor = EntityRenderer::calculatePulseColor(backgroundColor, _pulseProperties, _created); - layered = _renderLayer != RenderLayer::WORLD; + forward = _renderLayer != RenderLayer::WORLD || args->_renderMethod == render::Args::FORWARD; }); // Render background @@ -187,7 +187,7 @@ void TextEntityRenderer::doRender(RenderArgs* args) { gpu::Batch& batch = *args->_batch; // FIXME: we need to find a better way of rendering text so we don't have to do this - if (layered) { + if (forward) { DependencyManager::get()->setupKeyLightBatch(args, batch); } @@ -199,7 +199,7 @@ void TextEntityRenderer::doRender(RenderArgs* args) { if (backgroundColor.a > 0.0f) { batch.setModelTransform(transformToTopLeft); auto geometryCache = DependencyManager::get(); - geometryCache->bindSimpleProgram(batch, false, backgroundColor.a < 1.0f, false, false, false, true, layered); + geometryCache->bindSimpleProgram(batch, false, backgroundColor.a < 1.0f, false, false, false, true, forward); geometryCache->renderQuad(batch, minCorner, maxCorner, backgroundColor, _geometryID); } @@ -210,7 +210,7 @@ void TextEntityRenderer::doRender(RenderArgs* args) { batch.setModelTransform(transformToTopLeft); glm::vec2 bounds = glm::vec2(dimensions.x - (_leftMargin + _rightMargin), dimensions.y - (_topMargin + _bottomMargin)); - _textRenderer->draw(batch, _leftMargin / scale, -_topMargin / scale, _text, textColor, bounds / scale, layered); + _textRenderer->draw(batch, _leftMargin / scale, -_topMargin / scale, _text, textColor, bounds / scale, forward); } } diff --git a/libraries/procedural/src/procedural/Procedural.cpp b/libraries/procedural/src/procedural/Procedural.cpp index 9940da0b9a..dbdf9cc7d1 100644 --- a/libraries/procedural/src/procedural/Procedural.cpp +++ b/libraries/procedural/src/procedural/Procedural.cpp @@ -288,6 +288,7 @@ void Procedural::prepare(gpu::Batch& batch, recompiledShader = true; } + // FIXME: need to handle forward rendering batch.setPipeline(recompiledShader ? _proceduralPipelines[key] : pipeline->second); if (_shaderDirty || _uniformsDirty) { diff --git a/libraries/render-utils/src/GeometryCache.cpp b/libraries/render-utils/src/GeometryCache.cpp index 2e762a0107..7bd6f88d71 100644 --- a/libraries/render-utils/src/GeometryCache.cpp +++ b/libraries/render-utils/src/GeometryCache.cpp @@ -37,8 +37,6 @@ #include "DeferredLightingEffect.h" -#include - namespace gr { using graphics::slot::texture::Texture; using graphics::slot::buffer::Buffer; @@ -115,6 +113,8 @@ static const uint SHAPE_NORMALS_OFFSET = offsetof(GeometryCache::ShapeVertex, no static const uint SHAPE_TEXCOORD0_OFFSET = offsetof(GeometryCache::ShapeVertex, uv); static const uint SHAPE_TANGENT_OFFSET = offsetof(GeometryCache::ShapeVertex, tangent); +std::map, gpu::PipelinePointer> GeometryCache::_gridPipelines; + void GeometryCache::computeSimpleHullPointListForShape(const int entityShape, const glm::vec3 &entityExtents, QVector &outPointList) { auto geometryCache = DependencyManager::get(); @@ -714,11 +714,13 @@ QHash GeometryCache::_simplePrograms; gpu::ShaderPointer GeometryCache::_simpleShader; gpu::ShaderPointer GeometryCache::_transparentShader; gpu::ShaderPointer GeometryCache::_unlitShader; +gpu::ShaderPointer GeometryCache::_simpleFadeShader; +gpu::ShaderPointer GeometryCache::_unlitFadeShader; gpu::ShaderPointer GeometryCache::_forwardSimpleShader; gpu::ShaderPointer GeometryCache::_forwardTransparentShader; gpu::ShaderPointer GeometryCache::_forwardUnlitShader; -gpu::ShaderPointer GeometryCache::_simpleFadeShader; -gpu::ShaderPointer GeometryCache::_unlitFadeShader; +gpu::ShaderPointer GeometryCache::_forwardSimpleFadeShader; +gpu::ShaderPointer GeometryCache::_forwardUnlitFadeShader; render::ShapePipelinePointer GeometryCache::_simpleOpaquePipeline; render::ShapePipelinePointer GeometryCache::_simpleTransparentPipeline; @@ -740,16 +742,13 @@ render::ShapePipelinePointer GeometryCache::shapePipelineFactory(const render::S if (key.isFaded()) { if (key.isTranslucent()) { return _simpleTransparentFadePipeline; - } - else { + } else { return _simpleOpaqueFadePipeline; } - } - else { + } else { if (key.isTranslucent()) { return _simpleTransparentPipeline; - } - else { + } else { return _simpleOpaquePipeline; } } @@ -805,6 +804,8 @@ void GeometryCache::initializeShapePipelines() { _simpleTransparentPipeline = getShapePipeline(false, true, true, false); _forwardSimpleOpaquePipeline = getShapePipeline(false, false, true, false, false, true); _forwardSimpleTransparentPipeline = getShapePipeline(false, true, true, false, false, true); + + // FIXME: these need forward pipelines _simpleOpaqueFadePipeline = getFadingShapePipeline(false, false, false, false, false); _simpleTransparentFadePipeline = getFadingShapePipeline(false, true, false, false, false); _simpleWirePipeline = getShapePipeline(false, false, true, true); @@ -823,11 +824,11 @@ render::ShapePipelinePointer GeometryCache::getShapePipeline(bool textured, bool } render::ShapePipelinePointer GeometryCache::getFadingShapePipeline(bool textured, bool transparent, bool culled, - bool unlit, bool depthBias) { + bool unlit, bool depthBias, bool forward) { auto fadeEffect = DependencyManager::get(); auto fadeBatchSetter = fadeEffect->getBatchSetter(); auto fadeItemSetter = fadeEffect->getItemUniformSetter(); - return std::make_shared(getSimplePipeline(textured, transparent, culled, unlit, depthBias, true), nullptr, + return std::make_shared(getSimplePipeline(textured, transparent, culled, unlit, depthBias, true, true, forward), nullptr, [fadeBatchSetter, fadeItemSetter](const render::ShapePipeline& shapePipeline, gpu::Batch& batch, render::Args* args) { batch.setResourceTexture(gr::Texture::MaterialAlbedo, DependencyManager::get()->getWhiteTexture()); fadeBatchSetter(shapePipeline, batch, args); @@ -937,7 +938,7 @@ void GeometryCache::renderWireSphere(gpu::Batch& batch, const glm::vec4& color) void GeometryCache::renderGrid(gpu::Batch& batch, const glm::vec2& minCorner, const glm::vec2& maxCorner, int majorRows, int majorCols, float majorEdge, int minorRows, int minorCols, float minorEdge, - const glm::vec4& color, int id) { + const glm::vec4& color, bool forward, int id) { Vec2FloatPair majorKey(glm::vec2(majorRows, majorCols), majorEdge); Vec2FloatPair minorKey(glm::vec2(minorRows, minorCols), minorEdge); Vec2FloatPairPair key(majorKey, minorKey); @@ -970,7 +971,7 @@ void GeometryCache::renderGrid(gpu::Batch& batch, const glm::vec2& minCorner, co } // Set the grid pipeline - useGridPipeline(batch, gridBuffer, color.a < 1.0f); + useGridPipeline(batch, gridBuffer, color.a < 1.0f, forward); static const glm::vec2 MIN_TEX_COORD(0.0f, 0.0f); static const glm::vec2 MAX_TEX_COORD(1.0f, 1.0f); @@ -2038,39 +2039,34 @@ void GeometryCache::useSimpleDrawPipeline(gpu::Batch& batch, bool noBlend) { } } -void GeometryCache::useGridPipeline(gpu::Batch& batch, GridBuffer gridBuffer, bool transparent) { - if (!_gridPipelineOpaque || !_gridPipelineTransparent) { +void GeometryCache::useGridPipeline(gpu::Batch& batch, GridBuffer gridBuffer, bool transparent, bool forward) { + if (_gridPipelines.empty()) { + using namespace shader::render_utils::program; const float DEPTH_BIAS = 0.001f; - // FIXME: need forward pipelines - { - auto program = gpu::Shader::createProgram(shader::render_utils::program::grid); - auto state = std::make_shared(); - state->setDepthTest(true, true, gpu::LESS_EQUAL); - state->setBlendFunction(false, - gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, - gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); - PrepareStencil::testMaskDrawShape(*state); - state->setCullMode(gpu::State::CULL_NONE); - state->setDepthBias(DEPTH_BIAS); - _gridPipelineOpaque = gpu::Pipeline::create(program, state); - } + static const std::vector> keys = { + std::make_tuple(false, false, grid), std::make_tuple(false, true, forward_grid), std::make_tuple(true, false, grid_translucent), std::make_tuple(true, true, forward_grid_translucent) + }; - { - auto program = gpu::Shader::createProgram(shader::render_utils::program::grid_translucent); - auto state = std::make_shared(); + for (auto& key : keys) { + gpu::StatePointer state = gpu::StatePointer(new gpu::State()); state->setDepthTest(true, true, gpu::LESS_EQUAL); - state->setBlendFunction(true, + if (std::get<0>(key)) { + PrepareStencil::testMask(*state); + } else { + PrepareStencil::testMaskDrawShape(*state); + } + state->setBlendFunction(std::get<0>(key), gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); - PrepareStencil::testMask(*state); state->setCullMode(gpu::State::CULL_NONE); state->setDepthBias(DEPTH_BIAS); - _gridPipelineTransparent = gpu::Pipeline::create(program, state); + + _gridPipelines[{std::get<0>(key), std::get<1>(key)}] = gpu::Pipeline::create(gpu::Shader::createProgram(std::get<2>(key)), state); } } - batch.setPipeline(transparent ? _gridPipelineTransparent : _gridPipelineOpaque); + batch.setPipeline(_gridPipelines[{ transparent, forward }]); batch.setUniformBuffer(0, gridBuffer); } @@ -2162,6 +2158,7 @@ void GeometryCache::bindWebBrowserProgram(gpu::Batch& batch, bool transparent) { gpu::PipelinePointer GeometryCache::getWebBrowserProgram(bool transparent) { static std::once_flag once; std::call_once(once, [&]() { + // FIXME: need a forward pipeline for this buildWebShader(shader::render_utils::program::simple_opaque_web_browser, false, _simpleOpaqueWebBrowserShader, _simpleOpaqueWebBrowserPipeline); buildWebShader(shader::render_utils::program::simple_transparent_web_browser, true, _simpleTransparentWebBrowserShader, _simpleTransparentWebBrowserPipeline); }); @@ -2197,22 +2194,21 @@ gpu::PipelinePointer GeometryCache::getSimplePipeline(bool textured, bool transp _forwardSimpleShader = gpu::Shader::createProgram(forward_simple_textured); _forwardTransparentShader = gpu::Shader::createProgram(forward_simple_textured_transparent); _forwardUnlitShader = gpu::Shader::createProgram(forward_simple_textured_unlit); - if (DISABLE_DEFERRED) { - _simpleShader = _forwardSimpleShader; - _transparentShader = _forwardTransparentShader; - _unlitShader = _forwardUnlitShader; - } else { - _simpleShader = gpu::Shader::createProgram(simple_textured); - _transparentShader = gpu::Shader::createProgram(simple_transparent_textured); - _unlitShader = gpu::Shader::createProgram(simple_textured_unlit); - } + + _simpleShader = gpu::Shader::createProgram(simple_textured); + _transparentShader = gpu::Shader::createProgram(simple_transparent_textured); + _unlitShader = gpu::Shader::createProgram(simple_textured_unlit); }); } else { static std::once_flag once; std::call_once(once, [&]() { using namespace shader::render_utils::program; - _simpleFadeShader = gpu::Shader::createProgram(DISABLE_DEFERRED ? forward_simple_textured : simple_textured_fade); - _unlitFadeShader = gpu::Shader::createProgram(DISABLE_DEFERRED ? forward_simple_textured_unlit : simple_textured_unlit_fade); + // FIXME: these aren't right... + _forwardSimpleFadeShader = gpu::Shader::createProgram(forward_simple_textured); + _forwardUnlitFadeShader = gpu::Shader::createProgram(forward_simple_textured_unlit); + + _simpleFadeShader = gpu::Shader::createProgram(simple_textured_fade); + _unlitFadeShader = gpu::Shader::createProgram(simple_textured_unlit_fade); }); } @@ -2240,8 +2236,8 @@ gpu::PipelinePointer GeometryCache::getSimplePipeline(bool textured, bool transp gpu::ShaderPointer program; if (config.isForward()) { - program = (config.isUnlit()) ? (config.isFading() ? _unlitFadeShader : _forwardUnlitShader) : - (config.isFading() ? _simpleFadeShader : (config.isTransparent() ? _forwardTransparentShader : _forwardSimpleShader)); + program = (config.isUnlit()) ? (config.isFading() ? _forwardUnlitFadeShader : _forwardUnlitShader) : + (config.isFading() ? _forwardSimpleFadeShader : (config.isTransparent() ? _forwardTransparentShader : _forwardSimpleShader)); } else { program = (config.isUnlit()) ? (config.isFading() ? _unlitFadeShader : _unlitShader) : (config.isFading() ? _simpleFadeShader : (config.isTransparent() ? _transparentShader : _simpleShader)); diff --git a/libraries/render-utils/src/GeometryCache.h b/libraries/render-utils/src/GeometryCache.h index 4ff061786a..a42b059a8c 100644 --- a/libraries/render-utils/src/GeometryCache.h +++ b/libraries/render-utils/src/GeometryCache.h @@ -266,7 +266,7 @@ public: void renderGrid(gpu::Batch& batch, const glm::vec2& minCorner, const glm::vec2& maxCorner, int majorRows, int majorCols, float majorEdge, int minorRows, int minorCols, float minorEdge, - const glm::vec4& color, int id); + const glm::vec4& color, bool forward, int id); void renderBevelCornersRect(gpu::Batch& batch, int x, int y, int width, int height, int bevelDistance, const glm::vec4& color, int id); @@ -400,9 +400,8 @@ private: glm::vec4 edge; }; using GridBuffer = gpu::BufferView; - void useGridPipeline(gpu::Batch& batch, GridBuffer gridBuffer, bool isLayered); - gpu::PipelinePointer _gridPipelineOpaque; - gpu::PipelinePointer _gridPipelineTransparent; + void useGridPipeline(gpu::Batch& batch, GridBuffer gridBuffer, bool transparent, bool forward); + static std::map, gpu::PipelinePointer> _gridPipelines; class BatchItemDetails { public: @@ -460,11 +459,14 @@ private: static gpu::ShaderPointer _simpleShader; static gpu::ShaderPointer _transparentShader; static gpu::ShaderPointer _unlitShader; + static gpu::ShaderPointer _simpleFadeShader; + static gpu::ShaderPointer _unlitFadeShader; static gpu::ShaderPointer _forwardSimpleShader; static gpu::ShaderPointer _forwardTransparentShader; static gpu::ShaderPointer _forwardUnlitShader; - static gpu::ShaderPointer _simpleFadeShader; - static gpu::ShaderPointer _unlitFadeShader; + static gpu::ShaderPointer _forwardSimpleFadeShader; + static gpu::ShaderPointer _forwardUnlitFadeShader; + static render::ShapePipelinePointer _simpleOpaquePipeline; static render::ShapePipelinePointer _simpleTransparentPipeline; static render::ShapePipelinePointer _forwardSimpleOpaquePipeline; @@ -483,7 +485,7 @@ private: static render::ShapePipelinePointer getShapePipeline(bool textured = false, bool transparent = false, bool culled = true, bool unlit = false, bool depthBias = false, bool forward = false); static render::ShapePipelinePointer getFadingShapePipeline(bool textured = false, bool transparent = false, bool culled = true, - bool unlit = false, bool depthBias = false); + bool unlit = false, bool depthBias = false, bool forward = false); }; #endif // hifi_GeometryCache_h diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 7d0119a0f2..003a95e46d 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -1033,7 +1033,7 @@ void Model::removeFromScene(const render::ScenePointer& scene, render::Transacti _renderInfoHasTransparent = false; } -void Model::renderDebugMeshBoxes(gpu::Batch& batch) { +void Model::renderDebugMeshBoxes(gpu::Batch& batch, bool forward) { int colorNdx = 0; _mutex.lock(); @@ -1042,7 +1042,7 @@ void Model::renderDebugMeshBoxes(gpu::Batch& batch) { Transform meshToWorld(meshToWorldMatrix); batch.setModelTransform(meshToWorld); - DependencyManager::get()->bindSimpleProgram(batch, false, false, false, true, true); + DependencyManager::get()->bindSimpleProgram(batch, false, false, false, true, true, forward); for (auto& meshTriangleSets : _modelSpaceMeshTriangleSets) { for (auto &partTriangleSet : meshTriangleSets) { diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index 7844e9bc41..7c861a3bc1 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -347,7 +347,7 @@ public: const QMap& getRenderItems() const { return _modelMeshRenderItemsMap; } BlendShapeOperator getModelBlendshapeOperator() const { return _modelBlendshapeOperator; } - void renderDebugMeshBoxes(gpu::Batch& batch); + void renderDebugMeshBoxes(gpu::Batch& batch, bool forward); int getResourceDownloadAttempts() { return _renderWatcher.getResourceDownloadAttempts(); } int getResourceDownloadAttemptsRemaining() { return _renderWatcher.getResourceDownloadAttemptsRemaining(); } diff --git a/libraries/render-utils/src/RenderCommonTask.h b/libraries/render-utils/src/RenderCommonTask.h index b43a10aa7b..4f72600d34 100644 --- a/libraries/render-utils/src/RenderCommonTask.h +++ b/libraries/render-utils/src/RenderCommonTask.h @@ -137,4 +137,16 @@ public: void run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& output); }; +class SetRenderMethod { +public: + using JobModel = render::Job::Model; + + SetRenderMethod(render::Args::RenderMethod method) : _method(method) {} + + void run(const render::RenderContextPointer& renderContext) { renderContext->args->_renderMethod = _method; } + +protected: + render::Args::RenderMethod _method; +}; + #endif // hifi_RenderDeferredTask_h diff --git a/libraries/render-utils/src/RenderForwardTask.cpp b/libraries/render-utils/src/RenderForwardTask.cpp index 5e30308a05..de55f3f4ff 100755 --- a/libraries/render-utils/src/RenderForwardTask.cpp +++ b/libraries/render-utils/src/RenderForwardTask.cpp @@ -48,6 +48,8 @@ using namespace render; extern void initForwardPipelines(ShapePlumber& plumber); void RenderForwardTask::build(JobModel& task, const render::Varying& input, render::Varying& output) { + task.addJob("SetRenderMethodTask", render::Args::FORWARD); + // Prepare the ShapePipelines auto fadeEffect = DependencyManager::get(); ShapePlumberPointer shapePlumber = std::make_shared(); diff --git a/libraries/render-utils/src/RenderViewTask.cpp b/libraries/render-utils/src/RenderViewTask.cpp index a38769165b..ffaecedb0b 100644 --- a/libraries/render-utils/src/RenderViewTask.cpp +++ b/libraries/render-utils/src/RenderViewTask.cpp @@ -11,12 +11,15 @@ #include "RenderViewTask.h" #include "RenderShadowTask.h" +#include "RenderCommonTask.h" #include "RenderDeferredTask.h" #include "RenderForwardTask.h" -#include +#include void RenderShadowsAndDeferredTask::build(JobModel& task, const render::Varying& input, render::Varying& output, render::CullFunctor cullFunctor, uint8_t tagBits, uint8_t tagMask) { + task.addJob("SetRenderMethodTask", render::Args::DEFERRED); + const auto items = input.getN(0); const auto lightingModel = input.getN(1); const auto lightingStageFramesAndZones = input.getN(2); @@ -31,9 +34,9 @@ void RenderShadowsAndDeferredTask::build(JobModel& task, const render::Varying& } void DeferredForwardSwitchJob::build(JobModel& task, const render::Varying& input, render::Varying& output, render::CullFunctor cullFunctor, uint8_t tagBits, uint8_t tagMask) { - task.addBranch("RenderShadowsAndDeferredTask", 0, input, cullFunctor, tagBits, tagMask); + task.addBranch("RenderShadowsAndDeferredTask", RENDER_FORWARD ? 1 : 0, input, cullFunctor, tagBits, tagMask); - task.addBranch("RenderForwardTask", 1, input); + task.addBranch("RenderForwardTask", RENDER_FORWARD ? 0 : 1, input); } void RenderViewTask::build(JobModel& task, const render::Varying& input, render::Varying& output, render::CullFunctor cullFunctor, uint8_t tagBits, uint8_t tagMask) { @@ -45,11 +48,11 @@ void RenderViewTask::build(JobModel& task, const render::Varying& input, render: // Assemble the lighting stages current frames const auto lightingStageFramesAndZones = task.addJob("AssembleStages", items); - if (!DISABLE_DEFERRED) { +#ifndef Q_OS_ANDROID const auto deferredForwardIn = DeferredForwardSwitchJob::Input(items, lightingModel, lightingStageFramesAndZones).asVarying(); task.addJob("DeferredForwardSwitch", deferredForwardIn, cullFunctor, tagBits, tagMask); - } else { +#else const auto renderInput = RenderForwardTask::Input(items, lightingModel, lightingStageFramesAndZones).asVarying(); task.addJob("RenderForwardTask", renderInput); - } +#endif } diff --git a/libraries/render-utils/src/TextRenderer3D.cpp b/libraries/render-utils/src/TextRenderer3D.cpp index 8ef0dc0d73..d3ea20273e 100644 --- a/libraries/render-utils/src/TextRenderer3D.cpp +++ b/libraries/render-utils/src/TextRenderer3D.cpp @@ -67,11 +67,11 @@ float TextRenderer3D::getFontSize() const { } void TextRenderer3D::draw(gpu::Batch& batch, float x, float y, const QString& str, const glm::vec4& color, - const glm::vec2& bounds, bool layered) { + const glm::vec2& bounds, bool forward) { // The font does all the OpenGL work if (_font) { _color = color; - _font->drawString(batch, _drawInfo, str, _color, _effectType, { x, y }, bounds, layered); + _font->drawString(batch, _drawInfo, str, _color, _effectType, { x, y }, bounds, forward); } } diff --git a/libraries/render-utils/src/TextRenderer3D.h b/libraries/render-utils/src/TextRenderer3D.h index 6c91411e1d..ce4dd9f9e5 100644 --- a/libraries/render-utils/src/TextRenderer3D.h +++ b/libraries/render-utils/src/TextRenderer3D.h @@ -38,8 +38,8 @@ public: glm::vec2 computeExtent(const QString& str) const; float getFontSize() const; // Pixel size - void draw(gpu::Batch& batch, float x, float y, const QString& str, const glm::vec4& color = glm::vec4(1.0f), - const glm::vec2& bounds = glm::vec2(-1.0f), bool layered = false); + void draw(gpu::Batch& batch, float x, float y, const QString& str, const glm::vec4& color, + const glm::vec2& bounds, bool forward); private: TextRenderer3D(const char* family, float pointSize, int weight = -1, bool italic = false, diff --git a/libraries/render-utils/src/forward_grid.slf b/libraries/render-utils/src/forward_grid.slf new file mode 100644 index 0000000000..e34794bfed --- /dev/null +++ b/libraries/render-utils/src/forward_grid.slf @@ -0,0 +1,40 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// Created by Sam Gondelman on 5/9/19 +// Copyright 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 gpu/ShaderConstants.h@> +<@include gpu/Paint.slh@> + +struct Grid { + vec4 period; + vec4 offset; + vec4 edge; +}; + +LAYOUT(binding=0) uniform gridBuffer { + Grid grid; +}; + +layout(location=GPU_ATTR_TEXCOORD0) in vec2 varTexCoord0; +layout(location=GPU_ATTR_COLOR) in vec4 varColor; + +layout(location=0) out vec4 _fragColor0; + +void main(void) { + float alpha = mix(paintGridMajorMinor(varTexCoord0, grid.offset, grid.period, grid.edge), + paintGrid(varTexCoord0, grid.offset.xy, grid.period.xy, grid.edge.xy), + float(grid.edge.z == 0.0)); + + if (alpha < 0.0001) { + discard; + } + + _fragColor0 = vec4(varColor.xyz, 1.0); +} diff --git a/libraries/render-utils/src/forward_grid_translucent.slf b/libraries/render-utils/src/forward_grid_translucent.slf new file mode 100644 index 0000000000..df0494a22e --- /dev/null +++ b/libraries/render-utils/src/forward_grid_translucent.slf @@ -0,0 +1,41 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// Created by Sam Gondelman on 5/9/19 +// Copyright 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 gpu/ShaderConstants.h@> +<@include gpu/Paint.slh@> + +struct Grid { + vec4 period; + vec4 offset; + vec4 edge; +}; + +LAYOUT(binding=0) uniform gridBuffer { + Grid grid; +}; + +layout(location=GPU_ATTR_TEXCOORD0) in vec2 varTexCoord0; +layout(location=GPU_ATTR_COLOR) in vec4 varColor; + +layout(location=0) out vec4 _fragColor0; + +void main(void) { + float alpha = mix(paintGridMajorMinor(varTexCoord0, grid.offset, grid.period, grid.edge), + paintGrid(varTexCoord0, grid.offset.xy, grid.period.xy, grid.edge.xy), + float(grid.edge.z == 0.0)); + alpha *= varColor.w; + + if (alpha < 0.0001) { + discard; + } + + _fragColor0 = vec4(varColor.xyz, alpha); +} diff --git a/libraries/render-utils/src/forward_parabola.slf b/libraries/render-utils/src/forward_parabola.slf new file mode 100644 index 0000000000..b0def6db6b --- /dev/null +++ b/libraries/render-utils/src/forward_parabola.slf @@ -0,0 +1,18 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// Created by Sam Gondelman on 5/9/19 +// Copyright 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 +// + +layout(location=0) in vec4 _color; + +layout(location=0) out vec4 _fragColor0; + +void main(void) { + _fragColor0 = _color; +} diff --git a/libraries/render-utils/src/parabola_forward.slv b/libraries/render-utils/src/parabola_forward.slv deleted file mode 100644 index 4eb1456666..0000000000 --- a/libraries/render-utils/src/parabola_forward.slv +++ /dev/null @@ -1,7 +0,0 @@ -layout(location=0) in vec4 _color; - -layout(location=0) out vec4 _fragColor0; - -void main(void) { - _fragColor0 = _color; -} \ No newline at end of file diff --git a/libraries/render-utils/src/render-utils/forward_grid.slp b/libraries/render-utils/src/render-utils/forward_grid.slp new file mode 100644 index 0000000000..c81b208f63 --- /dev/null +++ b/libraries/render-utils/src/render-utils/forward_grid.slp @@ -0,0 +1 @@ +VERTEX standardTransformPNTC diff --git a/libraries/render-utils/src/render-utils/forward_grid_translucent.slp b/libraries/render-utils/src/render-utils/forward_grid_translucent.slp new file mode 100644 index 0000000000..c81b208f63 --- /dev/null +++ b/libraries/render-utils/src/render-utils/forward_grid_translucent.slp @@ -0,0 +1 @@ +VERTEX standardTransformPNTC diff --git a/libraries/render-utils/src/render-utils/forward_parabola.slp b/libraries/render-utils/src/render-utils/forward_parabola.slp new file mode 100644 index 0000000000..ab3f1d4126 --- /dev/null +++ b/libraries/render-utils/src/render-utils/forward_parabola.slp @@ -0,0 +1 @@ +VERTEX parabola diff --git a/libraries/render-utils/src/text/Font.cpp b/libraries/render-utils/src/text/Font.cpp index 364e24c5ac..c69db5e055 100644 --- a/libraries/render-utils/src/text/Font.cpp +++ b/libraries/render-utils/src/text/Font.cpp @@ -13,10 +13,13 @@ #include "FontFamilies.h" #include "../StencilMaskPass.h" -#include "DisableDeferred.h" - static std::mutex fontMutex; +gpu::PipelinePointer Font::_deferredPipeline; +gpu::PipelinePointer Font::_forwardPipeline; +gpu::PipelinePointer Font::_transparentPipeline; +gpu::Stream::FormatPointer Font::_format; + struct TextureVertex { glm::vec2 pos; glm::vec2 tex; @@ -218,13 +221,10 @@ void Font::read(QIODevice& in) { } void Font::setupGPU() { - if (!_initialized) { - _initialized = true; - + if (!_deferredPipeline) { // Setup render pipeline { { - gpu::ShaderPointer program = gpu::Shader::createProgram(shader::render_utils::program::forward_sdf_text3D); auto state = std::make_shared(); state->setCullMode(gpu::State::CULL_BACK); state->setDepthTest(true, true, gpu::LESS_EQUAL); @@ -232,25 +232,11 @@ void Font::setupGPU() { gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); PrepareStencil::testMaskDrawShape(*state); - _layeredPipeline = gpu::Pipeline::create(program, state); - } - - if (DISABLE_DEFERRED) { - _pipeline = _layeredPipeline; - } else { - gpu::ShaderPointer program = gpu::Shader::createProgram(shader::render_utils::program::sdf_text3D); - auto state = std::make_shared(); - state->setCullMode(gpu::State::CULL_BACK); - state->setDepthTest(true, true, gpu::LESS_EQUAL); - state->setBlendFunction(false, - gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, - gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); - PrepareStencil::testMaskDrawShape(*state); - _pipeline = gpu::Pipeline::create(program, state); + _deferredPipeline = gpu::Pipeline::create(gpu::Shader::createProgram(shader::render_utils::program::sdf_text3D), state); + _forwardPipeline = gpu::Pipeline::create(gpu::Shader::createProgram(shader::render_utils::program::forward_sdf_text3D), state); } { - gpu::ShaderPointer program = gpu::Shader::createProgram(shader::render_utils::program::sdf_text3D_transparent); auto state = std::make_shared(); state->setCullMode(gpu::State::CULL_BACK); state->setDepthTest(true, true, gpu::LESS_EQUAL); @@ -258,7 +244,7 @@ void Font::setupGPU() { gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); PrepareStencil::testMask(*state); - _transparentPipeline = gpu::Pipeline::create(program, state); + _transparentPipeline = gpu::Pipeline::create(gpu::Shader::createProgram(shader::render_utils::program::sdf_text3D_transparent), state); } } @@ -363,7 +349,7 @@ void Font::buildVertices(Font::DrawInfo& drawInfo, const QString& str, const glm } void Font::drawString(gpu::Batch& batch, Font::DrawInfo& drawInfo, const QString& str, const glm::vec4& color, - EffectType effectType, const glm::vec2& origin, const glm::vec2& bounds, bool layered) { + EffectType effectType, const glm::vec2& origin, const glm::vec2& bounds, bool forward) { if (str == "") { return; } @@ -390,7 +376,7 @@ void Font::drawString(gpu::Batch& batch, Font::DrawInfo& drawInfo, const QString } // need the gamma corrected color here - batch.setPipeline(color.a < 1.0f ? _transparentPipeline : (layered ? _layeredPipeline : _pipeline)); + batch.setPipeline(color.a < 1.0f ? _transparentPipeline : (forward ? _forwardPipeline : _deferredPipeline)); batch.setInputFormat(_format); batch.setInputBuffer(0, drawInfo.verticesBuffer, 0, _format->getChannels().at(0)._stride); batch.setResourceTexture(render_utils::slot::texture::TextFont, _texture); diff --git a/libraries/render-utils/src/text/Font.h b/libraries/render-utils/src/text/Font.h index 28af5bac43..893ab59981 100644 --- a/libraries/render-utils/src/text/Font.h +++ b/libraries/render-utils/src/text/Font.h @@ -46,7 +46,7 @@ public: // Render string to batch void drawString(gpu::Batch& batch, DrawInfo& drawInfo, const QString& str, const glm::vec4& color, EffectType effectType, - const glm::vec2& origin, const glm::vec2& bound, bool layered); + const glm::vec2& origin, const glm::vec2& bound, bool forward); static Pointer load(const QString& family); @@ -77,15 +77,13 @@ private: float _descent = 0.0f; float _spaceWidth = 0.0f; - bool _initialized = false; - - // gpu structures - gpu::PipelinePointer _pipeline; - gpu::PipelinePointer _layeredPipeline; - gpu::PipelinePointer _transparentPipeline; gpu::TexturePointer _texture; - gpu::Stream::FormatPointer _format; gpu::BufferStreamPointer _stream; + + static gpu::PipelinePointer _deferredPipeline; + static gpu::PipelinePointer _forwardPipeline; + static gpu::PipelinePointer _transparentPipeline; + static gpu::Stream::FormatPointer _format; }; #endif diff --git a/libraries/render/src/render/Args.h b/libraries/render/src/render/Args.h index 953a0b8223..7821692a60 100644 --- a/libraries/render/src/render/Args.h +++ b/libraries/render/src/render/Args.h @@ -64,6 +64,7 @@ namespace render { public: enum RenderMode { DEFAULT_RENDER_MODE, SHADOW_RENDER_MODE, MIRROR_RENDER_MODE, SECONDARY_CAMERA_RENDER_MODE }; enum DisplayMode { MONO, STEREO_MONITOR, STEREO_HMD }; + enum RenderMethod { DEFERRED, FORWARD }; enum DebugFlags { RENDER_DEBUG_NONE = 0, RENDER_DEBUG_HULLS = 1 @@ -77,6 +78,7 @@ namespace render { float lodAngleHalfTan = 0.1f, RenderMode renderMode = DEFAULT_RENDER_MODE, DisplayMode displayMode = MONO, + RenderMethod renderMethod = DEFERRED, DebugFlags debugFlags = RENDER_DEBUG_NONE, gpu::Batch* batch = nullptr) : _context(context), @@ -86,6 +88,7 @@ namespace render { _lodAngleHalfTanSq(lodAngleHalfTan * lodAngleHalfTan), _renderMode(renderMode), _displayMode(displayMode), + _renderMethod(renderMethod), _debugFlags(debugFlags), _batch(batch) { } @@ -117,6 +120,7 @@ namespace render { RenderMode _renderMode { DEFAULT_RENDER_MODE }; DisplayMode _displayMode { MONO }; + RenderMethod _renderMethod { DEFERRED }; DebugFlags _debugFlags { RENDER_DEBUG_NONE }; gpu::Batch* _batch = nullptr; diff --git a/libraries/shared/src/DisableDeferred.h b/libraries/shared/src/DisableDeferred.h deleted file mode 100644 index 9a1f9be117..0000000000 --- a/libraries/shared/src/DisableDeferred.h +++ /dev/null @@ -1,24 +0,0 @@ -// -// Created by Sam Gondelman on 3/7/19. -// Copyright 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_DisableDeferred_h -#define hifi_DisableDeferred_h - -#include -#include - -#if defined(USE_GLES) -static bool DISABLE_DEFERRED = true; -#else -static const QString RENDER_FORWARD{ "HIFI_RENDER_FORWARD" }; -static bool DISABLE_DEFERRED = QProcessEnvironment::systemEnvironment().contains(RENDER_FORWARD); -#endif - - -#endif // hifi_DisableDeferred_h - diff --git a/libraries/shared/src/RenderForward.h b/libraries/shared/src/RenderForward.h new file mode 100644 index 0000000000..e6fdef255b --- /dev/null +++ b/libraries/shared/src/RenderForward.h @@ -0,0 +1,24 @@ +// +// Created by Sam Gondelman on 3/7/19. +// Copyright 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_RenderForward_h +#define hifi_RenderForward_h + +#include +#include + +#if defined(USE_GLES) +// This isn't necessary since android forces the forward renderer, but just in case +static bool RENDER_FORWARD = true; +#else +static const QString RENDER_FORWARD_STRING { "HIFI_RENDER_FORWARD" }; +static bool RENDER_FORWARD = QProcessEnvironment::systemEnvironment().contains(RENDER_FORWARD_STRING); +#endif + + +#endif // hifi_RenderForward_h \ No newline at end of file diff --git a/libraries/task/src/task/Task.h b/libraries/task/src/task/Task.h index 87fb21d59b..cdc279ff36 100644 --- a/libraries/task/src/task/Task.h +++ b/libraries/task/src/task/Task.h @@ -460,7 +460,7 @@ public: void applyConfiguration() override { TimeProfiler probe("configure::" + JobConcept::getName()); jobConfigure(_data, *std::static_pointer_cast(Concept::_config)); - for (auto& branch : _branches) { + for (auto& branch : SwitchConcept::_branches) { branch.second.applyConfiguration(); } } @@ -468,13 +468,9 @@ public: void run(const ContextPointer& jobContext) override { auto config = std::static_pointer_cast(Concept::_config); if (config->isEnabled()) { - auto jobsIt = _branches.find(config->getBranch()); - if (jobsIt != _branches.end()) { + auto jobsIt = SwitchConcept::_branches.find(config->getBranch()); + if (jobsIt != SwitchConcept::_branches.end()) { jobsIt->second.run(jobContext); - if (jobContext->taskFlow.doAbortTask()) { - jobContext->taskFlow.reset(); - return; - } } } }