runtime switch for deferred/forward rendering

This commit is contained in:
SamGondelman 2019-04-26 12:56:01 -07:00
parent 164984b15d
commit ca5c7e3904
10 changed files with 129 additions and 41 deletions

View file

@ -243,11 +243,8 @@
#include "webbrowser/WebBrowserSuggestionsEngine.h"
#include <DesktopPreviewProvider.h>
#include "AboutUtil.h"
#include <DisableDeferred.h>
#if defined(Q_OS_WIN)
#include <VersionHelpers.h>
@ -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<Keyboard>()->registerKeyboardHighlighting();
});
}

View file

@ -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<SecondaryCameraJob>("SecondaryCamera");
task.addJob<RenderViewTask>("RenderSecondView", cullFunctor, isDeferred, render::ItemKey::TAG_BITS_1, render::ItemKey::TAG_BITS_1);
task.addJob<RenderViewTask>("RenderSecondView", cullFunctor, render::ItemKey::TAG_BITS_1, render::ItemKey::TAG_BITS_1);
task.addJob<EndSecondaryCameraFrame>("EndSecondaryCamera", cachedArg);
}

View file

@ -65,7 +65,7 @@ public:
using JobModel = render::Task::Model<SecondaryCameraRenderTask, Config>;
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

View file

@ -65,15 +65,15 @@ void GraphicsEngine::initializeGPU(GLWidget* glwidget) {
DependencyManager::get<TextureCache>()->setGPUContext(_gpuContext);
}
void GraphicsEngine::initializeRender(bool disableDeferred) {
void GraphicsEngine::initializeRender() {
// Set up the render engine
render::CullFunctor cullFunctor = LODManager::shouldRender;
_renderEngine->addJob<UpdateSceneTask>("UpdateScene");
#ifndef Q_OS_ANDROID
_renderEngine->addJob<SecondaryCameraRenderTask>("SecondaryCameraJob", cullFunctor, !disableDeferred);
_renderEngine->addJob<SecondaryCameraRenderTask>("SecondaryCameraJob", cullFunctor);
#endif
_renderEngine->addJob<RenderViewTask>("RenderMainView", cullFunctor, !disableDeferred, render::ItemKey::TAG_BITS_0, render::ItemKey::TAG_BITS_0);
_renderEngine->addJob<RenderViewTask>("RenderMainView", cullFunctor, render::ItemKey::TAG_BITS_0, render::ItemKey::TAG_BITS_0);
_renderEngine->load();
_renderEngine->registerScene(_renderScene);

View file

@ -44,7 +44,7 @@ public:
~GraphicsEngine();
void initializeGPU(GLWidget*);
void initializeRender(bool disableDeferred);
void initializeRender();
void startup();
void shutdown();

View file

@ -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 <DisableDeferred.h>
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<RenderFetchCullSortTask>("FetchCullSort", cullFunctor, tagBits, tagMask);
assert(items.canCast<RenderFetchCullSortTask::Output>());
@ -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<AssembleLightingStageTask>("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<AssembleLightingStageTask::Output>().get0()[0], lightingModel).asVarying();
const auto shadowTaskOut = task.addJob<RenderShadowTask>("RenderShadowTask", shadowTaskIn, cullFunctor, tagBits, tagMask);
const auto shadowTaskOut = task.addSwitchJob<RenderShadowTask>("RenderShadowTask", 0, shadowTaskIn, cullFunctor, tagBits, tagMask);
const auto renderInput = RenderDeferredTask::Input(items, lightingModel, lightingStageFramesAndZones, shadowTaskOut).asVarying();
task.addJob<RenderDeferredTask>("RenderDeferredTask", renderInput);
const auto renderDeferredInput = RenderDeferredTask::Input(items, lightingModel, lightingStageFramesAndZones, shadowTaskOut).asVarying();
task.addSwitchJob<RenderDeferredTask>("RenderDeferredTask", 0, renderDeferredInput);
const auto renderForwardInput = RenderForwardTask::Input(items, lightingModel, lightingStageFramesAndZones).asVarying();
task.addSwitchJob<RenderForwardTask>("RenderForwardTask", 1, renderForwardInput);
} else {
const auto renderInput = RenderForwardTask::Input(items, lightingModel, lightingStageFramesAndZones).asVarying();
task.addJob<RenderForwardTask>("Forward", renderInput);
task.addJob<RenderForwardTask>("RenderForwardTask", renderInput);
}
}

View file

@ -19,11 +19,12 @@
class RenderViewTask {
public:
using Input = RenderFetchCullSortTask::Output;
using JobModel = render::Task::ModelI<RenderViewTask, Input>;
using JobModel = render::Task::ModelIS<RenderViewTask, Input>;
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);
};

View file

@ -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();
}
}

View file

@ -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

View file

@ -15,6 +15,8 @@
#include "Config.h"
#include "Varying.h"
#include <unordered_map>
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<C>(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<C>(Concept::_config);
if (config->isEnabled()) {
for (auto job : TaskConcept::_jobs) {
@ -357,6 +340,81 @@ public:
template <class T, class O, class C = Config> using ModelO = TaskModel<T, C, None, O>;
template <class T, class I, class O, class C = Config> using ModelIO = TaskModel<T, C, I, O>;
template <class T, class C = SwitchConfig, class I = None, class O = None> class SwitchTaskModel : public TaskModel<T, C, I, O> {
public:
using Input = I;
std::unordered_map<uint8_t, Jobs> _jobsSwitch;
SwitchTaskModel(const std::string& name, const Varying& input, QConfigPointer config) : TaskModel<T, C, I, O>(name, input, config) {}
template <class... A>
static std::shared_ptr<SwitchTaskModel> create(const std::string& name, const Varying& input, A&&... args) {
auto model = std::make_shared<SwitchTaskModel>(name, input, std::make_shared<C>());
{
TimeProfiler probe("build::" + model->getName());
model->_data.build(*(model), model->_input, model->_output, std::forward<A>(args)...);
}
// Recreate the Config to use the templated type
model->createConfiguration();
model->applyConfiguration();
return model;
}
template <class... A>
static std::shared_ptr<SwitchTaskModel> create(const std::string& name, A&&... args) {
const auto input = Varying(Input());
return create(name, input, std::forward<A>(args)...);
}
void applyConfiguration() override {
TaskModel<T, C, I, O>::applyConfiguration();
for (auto& jobs : _jobsSwitch) {
for (auto& job : jobs.second) {
job.applyConfiguration();
}
}
}
void run(const ContextPointer& jobContext) override {
auto config = std::static_pointer_cast<C>(Concept::_config);
if (config->isEnabled()) {
// First we run all the setup jobs
TaskModel<T, C, I, O>::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 <class NT, class... NA> 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<NA>(args)...)));
// Conect the child config to this task's config
std::static_pointer_cast<TaskConfig>(Concept::getConfiguration())->connectChildConfig(jobs.back().getConfiguration(), name);
return jobs.back().getOutput();
}
template <class NT, class... NA> const Varying addSwitchJob(std::string name, uint8_t index, NA&&... args) {
const auto input = Varying(typename NT::JobModel::Input());
return addJob<NT>(name, index, input, std::forward<NA>(args)...);
}
};
template <class T, class I, class C = SwitchConfig> using ModelIS = SwitchTaskModel<T, C, I, None>;
// Create a new job in the Task's queue; returns the job's output
template <class T, class... A> const Varying addJob(std::string name, const Varying& input, A&&... args) {
return std::static_pointer_cast<TaskConcept>(JobType::_concept)->template addJob<T>(name, input, std::forward<A>(args)...);
@ -365,6 +423,13 @@ public:
const auto input = Varying(typename T::JobModel::Input());
return std::static_pointer_cast<TaskConcept>(JobType::_concept)->template addJob<T>(name, input, std::forward<A>(args)...);
}
template <class T, class... A> const Varying addSwitchJob(std::string name, uint8_t index, const Varying& input, A&&... args) {
return std::static_pointer_cast<SwitchTaskModel>(JobType::_concept)->template addSwitchJob<T>(name, index, input, std::forward<A>(args)...);
}
template <class T, class... A> const Varying addSwitchJob(std::string name, uint8_t index, A&&... args) {
const auto input = Varying(typename T::JobModel::Input());
return std::static_pointer_cast<SwitchTaskModel>(JobType::_concept)->template addSwitchJob<T>(name, index, input, std::forward<A>(args)...);
}
std::shared_ptr<Config> getConfiguration() {
return std::static_pointer_cast<Config>(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 <class T> using PersistentConfig = task::PersistentConfig<T>; \
using Job = task::Job<ContextType, TimeProfiler>; \
using Task = task::Task<ContextType, TimeProfiler>; \