Merge pull request #6930 from zzmp/feat/bubble-render-settings

Bubble up render settings from CPP to JS/QML
This commit is contained in:
samcake 2016-01-27 14:20:51 -08:00
commit f4e0352f61
31 changed files with 838 additions and 989 deletions

View file

@ -7,7 +7,7 @@ PreferencesDialog {
id: root
objectName: "GeneralPreferencesDialog"
title: "General Preferences"
showCategories: ["Snapshots", "Scripts", "Privacy", "Octree", "HMD", "Sixense Controllers"]
showCategories: ["Snapshots", "Scripts", "Privacy", "Octree", "HMD", "Sixense Controllers", "Graphics"]
property var settings: Settings {
category: root.objectName
property alias x: root.x

View file

@ -102,7 +102,6 @@
#include <RenderShadowTask.h>
#include <RenderDeferredTask.h>
#include <ResourceCache.h>
#include <RenderScriptingInterface.h>
#include <SceneScriptingInterface.h>
#include <RecordingScriptingInterface.h>
#include <ScriptCache.h>
@ -363,7 +362,6 @@ bool setupEssentials(int& argc, char** argv) {
#endif
DependencyManager::set<DiscoverabilityManager>();
DependencyManager::set<SceneScriptingInterface>();
DependencyManager::set<RenderScriptingInterface>();
DependencyManager::set<OffscreenUi>();
DependencyManager::set<AutoUpdater>();
DependencyManager::set<PathUtils>();
@ -675,12 +673,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
_offscreenContext->makeCurrent();
initializeGL();
// Start rendering
render::CullFunctor cullFunctor = LODManager::shouldRender;
_renderEngine->addTask(make_shared<RenderShadowTask>(cullFunctor));
_renderEngine->addTask(make_shared<RenderDeferredTask>(cullFunctor));
_renderEngine->registerScene(_main3DScene);
_offscreenContext->makeCurrent();
// Tell our entity edit sender about our known jurisdictions
@ -1151,9 +1143,17 @@ void Application::initializeGL() {
initDisplay();
qCDebug(interfaceapp, "Initialized Display.");
// Set up the render engine
render::CullFunctor cullFunctor = LODManager::shouldRender;
_renderEngine->addJob<RenderShadowTask>("RenderShadowTask", cullFunctor);
_renderEngine->addJob<RenderDeferredTask>("RenderDeferredTask", cullFunctor);
_renderEngine->registerScene(_main3DScene);
// TODO: Load a cached config file
// The UI can't be created until the primary OpenGL
// context is created, because it needs to share
// texture resources
// Needs to happen AFTER the render engine initialization to access its configuration
initializeUi();
qCDebug(interfaceapp, "Initialized Offscreen UI.");
_offscreenContext->makeCurrent();
@ -1251,7 +1251,7 @@ void Application::initializeUi() {
rootContext->setContextProperty("Paths", DependencyManager::get<PathUtils>().data());
rootContext->setContextProperty("HMD", DependencyManager::get<HMDScriptingInterface>().data());
rootContext->setContextProperty("Scene", DependencyManager::get<SceneScriptingInterface>().data());
rootContext->setContextProperty("Render", DependencyManager::get<RenderScriptingInterface>().data());
rootContext->setContextProperty("Render", _renderEngine->getConfiguration().get());
_glWidget->installEventFilter(offscreenUi.data());
offscreenUi->setMouseTranslator([=](const QPointF& pt) {
@ -3769,29 +3769,13 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se
{
PerformanceTimer perfTimer("EngineRun");
auto renderInterface = DependencyManager::get<RenderScriptingInterface>();
auto renderContext = renderInterface->getRenderContext();
renderArgs->_viewFrustum = getDisplayViewFrustum();
renderContext.setArgs(renderArgs);
bool occlusionStatus = Menu::getInstance()->isOptionChecked(MenuOption::DebugAmbientOcclusion);
bool shadowStatus = Menu::getInstance()->isOptionChecked(MenuOption::DebugShadows);
bool antialiasingStatus = Menu::getInstance()->isOptionChecked(MenuOption::Antialiasing);
bool showOwnedStatus = Menu::getInstance()->isOptionChecked(MenuOption::PhysicsShowOwned);
renderContext.setOptions(occlusionStatus, antialiasingStatus, showOwnedStatus, shadowStatus);
_renderEngine->setRenderContext(renderContext);
_renderEngine->getRenderContext()->args = renderArgs;
// Before the deferred pass, let's try to use the render engine
myAvatar->startRenderRun();
_renderEngine->run();
myAvatar->endRenderRun();
auto engineContext = _renderEngine->getRenderContext();
renderInterface->setItemCounts(engineContext->getItemsConfig());
renderInterface->setJobGPUTimes(engineContext->getAmbientOcclusion().gpuTime);
}
activeRenderingThread = nullptr;
@ -4200,7 +4184,7 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri
scriptEngine->registerFunction("HMD", "getHUDLookAtPosition3D", HMDScriptingInterface::getHUDLookAtPosition3D, 0);
scriptEngine->registerGlobalObject("Scene", DependencyManager::get<SceneScriptingInterface>().data());
scriptEngine->registerGlobalObject("Render", DependencyManager::get<RenderScriptingInterface>().data());
scriptEngine->registerGlobalObject("Render", _renderEngine->getConfiguration().get());
scriptEngine->registerGlobalObject("ScriptDiscoveryService", DependencyManager::get<ScriptEngines>().data());
}

View file

@ -32,6 +32,7 @@
#include "devices/Faceshift.h"
#include "input-plugins/SpacemouseManager.h"
#include "MainWindow.h"
#include "render/DrawStatus.h"
#include "scripting/MenuScriptingInterface.h"
#include "ui/AssetUploadDialogFactory.h"
#include "ui/DialogsManager.h"
@ -336,9 +337,6 @@ Menu::Menu() {
// Developer > Render >>>
MenuWrapper* renderOptionsMenu = developerMenu->addMenu("Render");
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::WorldAxes);
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::DebugAmbientOcclusion);
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::DebugShadows);
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Antialiasing);
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Stars, 0, true);
// Developer > Render > Ambient Light
@ -594,7 +592,11 @@ Menu::Menu() {
// Developer > Physics >>>
MenuWrapper* physicsOptionsMenu = developerMenu->addMenu("Physics");
addCheckableActionToQMenuAndActionHash(physicsOptionsMenu, MenuOption::PhysicsShowOwned);
{
auto drawStatusConfig = qApp->getRenderEngine()->getConfiguration()->getConfig<render::DrawStatus>();
addCheckableActionToQMenuAndActionHash(physicsOptionsMenu, MenuOption::PhysicsShowOwned,
0, false, drawStatusConfig, SLOT(setShowNetwork(bool)));
}
addCheckableActionToQMenuAndActionHash(physicsOptionsMenu, MenuOption::PhysicsShowHulls);
// Developer > Display Crash Options

View file

@ -152,7 +152,6 @@ namespace MenuOption {
const QString AnimDebugDrawAnimPose = "Debug Draw Animation";
const QString AnimDebugDrawDefaultPose = "Debug Draw Default Pose";
const QString AnimDebugDrawPosition= "Debug Draw Position";
const QString Antialiasing = "Antialiasing";
const QString AssetMigration = "ATP Asset Migration";
const QString Attachments = "Attachments...";
const QString AudioNetworkStats = "Audio Network Stats";
@ -186,8 +185,6 @@ namespace MenuOption {
const QString CopyPath = "Copy Path to Clipboard";
const QString CoupleEyelids = "Couple Eyelids";
const QString CrashInterface = "Crash Interface";
const QString DebugShadows = "Shadows";
const QString DebugAmbientOcclusion = "Ambient Occlusion";
const QString DecreaseAvatarSize = "Decrease Avatar Size";
const QString DeleteBookmark = "Delete Bookmark...";
const QString DisableActivityLogger = "Disable Activity Logger";
@ -248,8 +245,8 @@ namespace MenuOption {
const QString OutputMenu = "Display";
const QString PackageModel = "Package Model...";
const QString Pair = "Pair";
const QString PhysicsShowOwned = "Highlight Simulation Ownership";
const QString PhysicsShowHulls = "Draw Collision Hulls";
const QString PhysicsShowOwned = "Highlight Simulation Ownership";
const QString PipelineWarnings = "Log Render Pipeline Warnings";
const QString Preferences = "General...";
const QString Quit = "Quit";

View file

@ -24,6 +24,10 @@
#include "Snapshot.h"
#include "UserActivityLogger.h"
#include "AmbientOcclusionEffect.h"
#include "AntialiasingEffect.h"
#include "RenderShadowTask.h"
void setupPreferences() {
auto preferences = DependencyManager::get<Preferences>();
@ -310,4 +314,29 @@ void setupPreferences() {
preference->setStep(1);
preferences->addPreference(preference);
}
{
static const QString RENDER("Graphics");
auto renderConfig = qApp->getRenderEngine()->getConfiguration();
{
auto getter = [renderConfig]()->bool { return renderConfig->isJobEnabled<AmbientOcclusionEffect>(); };
auto setter = [renderConfig](bool enable) { renderConfig->setJobEnabled<AmbientOcclusionEffect>(enable); };
auto preference = new CheckPreference(RENDER, "Ambient Occlusion", getter, setter);
preferences->addPreference(preference);
}
{
auto getter = [renderConfig]()->bool { return renderConfig->isJobEnabled<Antialiasing>(); };
auto setter = [renderConfig](bool enable) { renderConfig->setJobEnabled<Antialiasing>(enable); };
auto preference = new CheckPreference(RENDER, "Antialiasing", getter, setter);
preferences->addPreference(preference);
}
{
auto getter = [renderConfig]()->bool { return renderConfig->isJobEnabled<RenderShadowTask>(); };
auto setter = [renderConfig](bool enable) { renderConfig->setJobEnabled<RenderShadowTask>(enable); };
auto preference = new CheckPreference(RENDER, "Shadows", getter, setter);
preferences->addPreference(preference);
}
}
}

View file

@ -21,6 +21,7 @@
#include <gpu/StandardShaderLib.h>
#include "RenderUtilsLogging.h"
#include "DeferredLightingEffect.h"
#include "AmbientOcclusionEffect.h"
#include "TextureCache.h"
#include "FramebufferCache.h"
@ -100,6 +101,82 @@ AmbientOcclusionEffect::AmbientOcclusionEffect() {
_parametersBuffer = gpu::BufferView(std::make_shared<gpu::Buffer>(sizeof(Parameters), (const gpu::Byte*) &parameters));
}
void AmbientOcclusionEffect::configure(const Config& config) {
DependencyManager::get<DeferredLightingEffect>()->setAmbientOcclusionEnabled(config.enabled);
bool shouldUpdateGaussian = false;
const double RADIUS_POWER = 6.0;
const auto& radius = config.radius;
if (radius != getRadius()) {
auto& current = _parametersBuffer.edit<Parameters>().radiusInfo;
current.x = radius;
current.y = radius * radius;
current.z = (float)(1.0 / pow((double)radius, RADIUS_POWER));
}
if (config.obscuranceLevel != getObscuranceLevel()) {
auto& current = _parametersBuffer.edit<Parameters>().radiusInfo;
current.w = config.obscuranceLevel;
}
if (config.falloffBias != getFalloffBias()) {
auto& current = _parametersBuffer.edit<Parameters>().ditheringInfo;
current.z = config.falloffBias;
}
if (config.edgeSharpness != getEdgeSharpness()) {
auto& current = _parametersBuffer.edit<Parameters>().blurInfo;
current.x = config.edgeSharpness;
}
if (config.blurDeviation != getBlurDeviation()) {
auto& current = _parametersBuffer.edit<Parameters>().blurInfo;
current.z = config.blurDeviation;
shouldUpdateGaussian = true;
}
if (config.numSpiralTurns != getNumSpiralTurns()) {
auto& current = _parametersBuffer.edit<Parameters>().sampleInfo;
current.z = config.numSpiralTurns;
}
if (config.numSamples != getNumSamples()) {
auto& current = _parametersBuffer.edit<Parameters>().sampleInfo;
current.x = config.numSamples;
current.y = 1.0f / config.numSamples;
}
const auto& resolutionLevel = config.resolutionLevel;
if (resolutionLevel != getResolutionLevel()) {
auto& current = _parametersBuffer.edit<Parameters>().resolutionInfo;
current.x = (float)resolutionLevel;
// Communicate the change to the Framebuffer cache
DependencyManager::get<FramebufferCache>()->setAmbientOcclusionResolutionLevel(resolutionLevel);
}
if (config.blurRadius != getBlurRadius()) {
auto& current = _parametersBuffer.edit<Parameters>().blurInfo;
current.y = (float)config.blurRadius;
shouldUpdateGaussian = true;
}
if (config.ditheringEnabled != isDitheringEnabled()) {
auto& current = _parametersBuffer.edit<Parameters>().ditheringInfo;
current.x = (float)config.ditheringEnabled;
}
if (config.borderingEnabled != isBorderingEnabled()) {
auto& current = _parametersBuffer.edit<Parameters>().ditheringInfo;
current.w = (float)config.borderingEnabled;
}
if (shouldUpdateGaussian) {
updateGaussianDistribution();
}
}
const gpu::PipelinePointer& AmbientOcclusionEffect::getPyramidPipeline() {
if (!_pyramidPipeline) {
auto vs = gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS();
@ -200,113 +277,16 @@ void AmbientOcclusionEffect::setDepthInfo(float nearZ, float farZ) {
_frameTransformBuffer.edit<FrameTransform>().depthInfo = glm::vec4(nearZ*farZ, farZ -nearZ, -farZ, 0.0f);
}
void AmbientOcclusionEffect::setResolutionLevel(int level) {
const int MAX_RESOLUTION_LEVEL = 4;
level = std::max(0, std::min(level, MAX_RESOLUTION_LEVEL));
if (level != getResolutionLevel()) {
auto& current = _parametersBuffer.edit<Parameters>().resolutionInfo;
current.x = (float)level;
// Communicate the change to the Framebuffer cache
DependencyManager::get<FramebufferCache>()->setAmbientOcclusionResolutionLevel(level);
}
}
void AmbientOcclusionEffect::setRadius(float radius) {
const double RADIUS_POWER = 6.0;
radius = std::max(0.01f, radius);
if (radius != getRadius()) {
auto& current = _parametersBuffer.edit<Parameters>().radiusInfo;
current.x = radius;
current.y = radius * radius;
current.z = (float)(1.0 / pow((double)radius, RADIUS_POWER));
}
}
void AmbientOcclusionEffect::setLevel(float level) {
level = std::max(0.01f, level);
if (level != getLevel()) {
auto& current = _parametersBuffer.edit<Parameters>().radiusInfo;
current.w = level;
}
}
void AmbientOcclusionEffect::setDithering(bool enabled) {
if (enabled != isDitheringEnabled()) {
auto& current = _parametersBuffer.edit<Parameters>().ditheringInfo;
current.x = (float)enabled;
}
}
void AmbientOcclusionEffect::setBordering(bool enabled) {
if (enabled != isBorderingEnabled()) {
auto& current = _parametersBuffer.edit<Parameters>().ditheringInfo;
current.w = (float)enabled;
}
}
void AmbientOcclusionEffect::setFalloffBias(float bias) {
bias = std::max(0.0f, std::min(bias, 0.2f));
if (bias != getFalloffBias()) {
auto& current = _parametersBuffer.edit<Parameters>().ditheringInfo;
current.z = (float)bias;
}
}
void AmbientOcclusionEffect::setNumSamples(int numSamples) {
numSamples = std::max(1.0f, (float) numSamples);
if (numSamples != getNumSamples()) {
auto& current = _parametersBuffer.edit<Parameters>().sampleInfo;
current.x = numSamples;
current.y = 1.0f / numSamples;
}
}
void AmbientOcclusionEffect::setNumSpiralTurns(float numTurns) {
numTurns = std::max(0.0f, (float)numTurns);
if (numTurns != getNumSpiralTurns()) {
auto& current = _parametersBuffer.edit<Parameters>().sampleInfo;
current.z = numTurns;
}
}
void AmbientOcclusionEffect::setEdgeSharpness(float sharpness) {
sharpness = std::max(0.0f, (float)sharpness);
if (sharpness != getEdgeSharpness()) {
auto& current = _parametersBuffer.edit<Parameters>().blurInfo;
current.x = sharpness;
}
}
void AmbientOcclusionEffect::setBlurRadius(int radius) {
const int MAX_BLUR_RADIUS = 6;
radius = std::max(0, std::min(MAX_BLUR_RADIUS, radius));
if (radius != getBlurRadius()) {
auto& current = _parametersBuffer.edit<Parameters>().blurInfo;
current.y = (float)radius;
updateGaussianDistribution();
}
}
void AmbientOcclusionEffect::setBlurDeviation(float deviation) {
deviation = std::max(0.0f, deviation);
if (deviation != getBlurDeviation()) {
auto& current = _parametersBuffer.edit<Parameters>().blurInfo;
current.z = deviation;
updateGaussianDistribution();
}
}
void AmbientOcclusionEffect::updateGaussianDistribution() {
auto coefs = _parametersBuffer.edit<Parameters>()._gaussianCoefs;
GaussianDistribution::evalSampling(coefs, Parameters::GAUSSIAN_COEFS_LENGTH, getBlurRadius(), getBlurDeviation());
}
void AmbientOcclusionEffect::run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext) {
assert(renderContext->getArgs());
assert(renderContext->getArgs()->_viewFrustum);
assert(renderContext->args);
assert(renderContext->args->_viewFrustum);
RenderArgs* args = renderContext->getArgs();
RenderArgs* args = renderContext->args;
auto framebufferCache = DependencyManager::get<FramebufferCache>();
auto depthBuffer = framebufferCache->getPrimaryDepthTexture();
@ -417,6 +397,8 @@ void AmbientOcclusionEffect::run(const render::SceneContextPointer& sceneContext
}
_gpuTimer.end(batch);
});
// Update the timer
std::static_pointer_cast<Config>(renderContext->jobConfig)->gpuTime = _gpuTimer.getAverage();
}

View file

@ -16,64 +16,78 @@
#include "render/DrawTask.h"
class AmbientOcclusionEffectConfig : public render::Job::Config {
Q_OBJECT
Q_PROPERTY(bool enabled MEMBER enabled NOTIFY dirty)
Q_PROPERTY(bool ditheringEnabled MEMBER ditheringEnabled NOTIFY dirty)
Q_PROPERTY(bool borderingEnabled MEMBER borderingEnabled NOTIFY dirty)
Q_PROPERTY(float radius MEMBER radius WRITE setRadius)
Q_PROPERTY(float obscuranceLevel MEMBER obscuranceLevel WRITE setObscuranceLevel)
Q_PROPERTY(float falloffBias MEMBER falloffBias WRITE setFalloffBias)
Q_PROPERTY(float edgeSharpness MEMBER edgeSharpness WRITE setEdgeSharpness)
Q_PROPERTY(float blurDeviation MEMBER blurDeviation WRITE setBlurDeviation)
Q_PROPERTY(float numSpiralTurns MEMBER numSpiralTurns WRITE setNumSpiralTurns)
Q_PROPERTY(int numSamples MEMBER numSamples WRITE setNumSamples)
Q_PROPERTY(int resolutionLevel MEMBER resolutionLevel WRITE setResolutionLevel)
Q_PROPERTY(int blurRadius MEMBER blurRadius WRITE setBlurRadius)
Q_PROPERTY(double gpuTime READ getGpuTime)
public:
AmbientOcclusionEffectConfig() : render::Job::Config(false) {}
const int MAX_RESOLUTION_LEVEL = 4;
const int MAX_BLUR_RADIUS = 6;
void setRadius(float newRadius) { radius = std::max(0.01f, newRadius); emit dirty(); }
void setObscuranceLevel(float level) { obscuranceLevel = std::max(0.01f, level); emit dirty(); }
void setFalloffBias(float bias) { falloffBias = std::max(0.0f, std::min(bias, 0.2f)); emit dirty(); }
void setEdgeSharpness(float sharpness) { edgeSharpness = std::max(0.0f, (float)sharpness); emit dirty(); }
void setBlurDeviation(float deviation) { blurDeviation = std::max(0.0f, deviation); emit dirty(); }
void setNumSpiralTurns(float turns) { numSpiralTurns = std::max(0.0f, (float)turns); emit dirty(); }
void setNumSamples(int samples) { numSamples = std::max(1.0f, (float)samples); emit dirty(); }
void setResolutionLevel(int level) { resolutionLevel = std::max(0, std::min(level, MAX_RESOLUTION_LEVEL)); emit dirty(); }
void setBlurRadius(int radius) { blurRadius = std::max(0, std::min(MAX_BLUR_RADIUS, radius)); emit dirty(); }
double getGpuTime() { return gpuTime; }
float radius{ 0.5f };
float obscuranceLevel{ 0.5f }; // intensify or dim down the obscurance effect
float falloffBias{ 0.01f };
float edgeSharpness{ 1.0f };
float blurDeviation{ 2.5f };
float numSpiralTurns{ 7.0f }; // defining an angle span to distribute the samples ray directions
int numSamples{ 11 };
int resolutionLevel{ 1 };
int blurRadius{ 4 }; // 0 means no blurring
bool ditheringEnabled{ true }; // randomize the distribution of rays per pixel, should always be true
bool borderingEnabled{ true }; // avoid evaluating information from non existing pixels out of the frame, should always be true
double gpuTime{ 0.0 };
signals:
void dirty();
};
class AmbientOcclusionEffect {
public:
using Config = AmbientOcclusionEffectConfig;
using JobModel = render::Job::Model<AmbientOcclusionEffect, Config>;
AmbientOcclusionEffect();
void configure(const Config& config);
void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext);
void setResolutionLevel(int level);
int getResolutionLevel() const { return _parametersBuffer.get<Parameters>().resolutionInfo.x; }
void setRadius(float radius);
float getRadius() const { return _parametersBuffer.get<Parameters>().radiusInfo.x; }
// Obscurance level which intensify or dim down the obscurance effect
void setLevel(float level);
float getLevel() const { return _parametersBuffer.get<Parameters>().radiusInfo.w; }
// On to randomize the distribution of rays per pixel, should always be true
void setDithering(bool enabled);
bool isDitheringEnabled() const { return _parametersBuffer.get<Parameters>().ditheringInfo.x; }
// On to avoid evaluating information from non existing pixels Out of the frame, should always be true
void setBordering(bool enabled);
bool isBorderingEnabled() const { return _parametersBuffer.get<Parameters>().ditheringInfo.w; }
// Faloff Bias
void setFalloffBias(float bias);
int getFalloffBias() const { return (int)_parametersBuffer.get<Parameters>().ditheringInfo.z; }
// Number of samples per pixel to evaluate the Obscurance
void setNumSamples(int numSamples);
int getNumSamples() const { return (int)_parametersBuffer.get<Parameters>().sampleInfo.x; }
// Number of spiral turns defining an angle span to distribute the samples ray directions
void setNumSpiralTurns(float numTurns);
float getNumSpiralTurns() const { return _parametersBuffer.get<Parameters>().sampleInfo.z; }
// Edge blurring setting
void setEdgeSharpness(float sharpness);
int getEdgeSharpness() const { return (int)_parametersBuffer.get<Parameters>().blurInfo.x; }
// Blurring Radius
// 0 means no blurring
const int MAX_BLUR_RADIUS = 6;
void setBlurRadius(int radius);
int getBlurRadius() const { return (int)_parametersBuffer.get<Parameters>().blurInfo.y; }
void setBlurDeviation(float deviation);
float getObscuranceLevel() const { return _parametersBuffer.get<Parameters>().radiusInfo.w; }
float getFalloffBias() const { return (float)_parametersBuffer.get<Parameters>().ditheringInfo.z; }
float getEdgeSharpness() const { return (float)_parametersBuffer.get<Parameters>().blurInfo.x; }
float getBlurDeviation() const { return _parametersBuffer.get<Parameters>().blurInfo.z; }
float getNumSpiralTurns() const { return _parametersBuffer.get<Parameters>().sampleInfo.z; }
int getNumSamples() const { return (int)_parametersBuffer.get<Parameters>().sampleInfo.x; }
int getResolutionLevel() const { return _parametersBuffer.get<Parameters>().resolutionInfo.x; }
int getBlurRadius() const { return (int)_parametersBuffer.get<Parameters>().blurInfo.y; }
bool isDitheringEnabled() const { return _parametersBuffer.get<Parameters>().ditheringInfo.x; }
bool isBorderingEnabled() const { return _parametersBuffer.get<Parameters>().ditheringInfo.w; }
double getGPUTime() const { return _gpuTimer.getAverage(); }
using JobModel = render::Task::Job::Model<AmbientOcclusionEffect>;
private:
void updateGaussianDistribution();
void setDepthInfo(float nearZ, float farZ);

View file

@ -92,14 +92,15 @@ const gpu::PipelinePointer& Antialiasing::getBlendPipeline() {
}
void Antialiasing::run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext) {
assert(renderContext->getArgs());
assert(renderContext->getArgs()->_viewFrustum);
assert(renderContext->args);
assert(renderContext->args->_viewFrustum);
if (renderContext->getArgs()->_renderMode == RenderArgs::MIRROR_RENDER_MODE) {
RenderArgs* args = renderContext->args;
if (args->_renderMode == RenderArgs::MIRROR_RENDER_MODE) {
return;
}
RenderArgs* args = renderContext->getArgs();
gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
batch.enableStereo(false);
batch.setViewportTransform(args->_viewport);

View file

@ -16,13 +16,21 @@
#include "render/DrawTask.h"
class AntiAliasingConfig : public render::Job::Config {
Q_OBJECT
Q_PROPERTY(bool enabled MEMBER enabled)
public:
AntiAliasingConfig() : render::Job::Config(false) {}
};
class Antialiasing {
public:
using Config = AntiAliasingConfig;
using JobModel = render::Job::Model<Antialiasing, Config>;
Antialiasing();
void configure(const Config& config) {}
void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext);
using JobModel = render::Task::Job::Model<Antialiasing>;
const gpu::PipelinePointer& getAntialiasingPipeline();
const gpu::PipelinePointer& getBlendPipeline();

View file

@ -27,7 +27,18 @@
using namespace render;
enum Slots {
void DebugDeferredBufferConfig::setMode(int newMode) {
if (newMode == mode) {
return;
} else if (newMode > DebugDeferredBuffer::CustomMode || newMode < 0) {
mode = DebugDeferredBuffer::CustomMode;
} else {
mode = newMode;
}
emit dirty();
}
enum Slot {
Diffuse = 0,
Normal,
Specular,
@ -39,6 +50,8 @@ enum Slots {
AmbientOcclusionBlurred
};
static const std::string DEFAULT_DIFFUSE_SHADER {
"vec4 getFragmentColor() {"
" return vec4(pow(texture(diffuseMap, uv).xyz, vec3(1.0 / 2.2)), 1.0);"
@ -129,7 +142,7 @@ DebugDeferredBuffer::DebugDeferredBuffer() {
_customPipelines.emplace(CUSTOM_FILE, pipeline);
}
std::string DebugDeferredBuffer::getShaderSourceCode(Modes mode, std::string customFile) {
std::string DebugDeferredBuffer::getShaderSourceCode(Mode mode, std::string customFile) {
switch (mode) {
case DiffuseMode:
return DEFAULT_DIFFUSE_SHADER;
@ -158,7 +171,7 @@ std::string DebugDeferredBuffer::getShaderSourceCode(Modes mode, std::string cus
return std::string();
}
bool DebugDeferredBuffer::pipelineNeedsUpdate(Modes mode, std::string customFile) const {
bool DebugDeferredBuffer::pipelineNeedsUpdate(Mode mode, std::string customFile) const {
if (mode != CustomMode) {
return !_pipelines[mode];
}
@ -175,7 +188,7 @@ bool DebugDeferredBuffer::pipelineNeedsUpdate(Modes mode, std::string customFile
return true;
}
const gpu::PipelinePointer& DebugDeferredBuffer::getPipeline(Modes mode, std::string customFile) {
const gpu::PipelinePointer& DebugDeferredBuffer::getPipeline(Mode mode, std::string customFile) {
if (pipelineNeedsUpdate(mode, customFile)) {
static const std::string VERTEX_SHADER { debug_deferred_buffer_vert };
static const std::string FRAGMENT_SHADER { debug_deferred_buffer_frag };
@ -221,18 +234,15 @@ const gpu::PipelinePointer& DebugDeferredBuffer::getPipeline(Modes mode, std::st
}
}
void DebugDeferredBuffer::configure(const Config& config) {
_mode = (Mode)config.mode;
_size = config.size;
}
void DebugDeferredBuffer::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
assert(renderContext->getArgs());
assert(renderContext->getArgs()->_viewFrustum);
RenderArgs* args = renderContext->getArgs();
// Guard against unspecified modes
auto mode = renderContext->_deferredDebugMode;
if (mode > (int)CustomMode) {
renderContext->_deferredDebugMode = -1;
return;
}
assert(renderContext->args);
assert(renderContext->args->_viewFrustum);
RenderArgs* args = renderContext->args;
gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
const auto geometryBuffer = DependencyManager::get<GeometryCache>();
@ -250,7 +260,7 @@ void DebugDeferredBuffer::run(const SceneContextPointer& sceneContext, const Ren
// TODO REMOVE: Temporary until UI
auto first = _customPipelines.begin()->first;
batch.setPipeline(getPipeline(Modes(renderContext->_deferredDebugMode), first));
batch.setPipeline(getPipeline(_mode, first));
batch.setResourceTexture(Diffuse, framebufferCache->getDeferredColorTexture());
batch.setResourceTexture(Normal, framebufferCache->getDeferredNormalTexture());
@ -263,8 +273,8 @@ void DebugDeferredBuffer::run(const SceneContextPointer& sceneContext, const Ren
batch.setResourceTexture(AmbientOcclusionBlurred, framebufferCache->getOcclusionBlurredTexture());
const glm::vec4 color(1.0f, 1.0f, 1.0f, 1.0f);
const glm::vec2 bottomLeft(renderContext->_deferredDebugSize.x, renderContext->_deferredDebugSize.y);
const glm::vec2 topRight(renderContext->_deferredDebugSize.z, renderContext->_deferredDebugSize.w);
const glm::vec2 bottomLeft(_size.x, _size.y);
const glm::vec2 topRight(_size.z, _size.w);
geometryBuffer->renderQuad(batch, bottomLeft, topRight, color);
});
}

View file

@ -16,16 +16,37 @@
#include <render/DrawTask.h>
class DebugDeferredBufferConfig : public render::Job::Config {
Q_OBJECT
Q_PROPERTY(bool enabled MEMBER enabled)
Q_PROPERTY(int mode MEMBER mode WRITE setMode)
Q_PROPERTY(glm::vec4 size MEMBER size NOTIFY dirty)
public:
DebugDeferredBufferConfig() : render::Job::Config(false) {}
void setMode(int newMode);
int mode{ 0 };
glm::vec4 size{ 0.0f, 0.0f, 0.0f, 0.0f };
signals:
void dirty();
};
class DebugDeferredBuffer {
public:
using JobModel = render::Task::Job::Model<DebugDeferredBuffer>;
using Config = DebugDeferredBufferConfig;
using JobModel = render::Job::Model<DebugDeferredBuffer, Config>;
DebugDeferredBuffer();
void configure(const Config& config);
void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext);
private:
enum Modes : uint8_t {
protected:
friend class DebugDeferredBufferConfig;
enum Mode : uint8_t {
// Use Mode suffix to avoid collisions
DiffuseMode = 0,
SpecularMode,
RoughnessMode,
@ -38,6 +59,11 @@ private:
AmbientOcclusionBlurredMode,
CustomMode // Needs to stay last
};
private:
Mode _mode;
glm::vec4 _size;
struct CustomPipeline {
gpu::PipelinePointer pipeline;
mutable QFileInfo info;
@ -45,9 +71,9 @@ private:
using StandardPipelines = std::array<gpu::PipelinePointer, CustomMode>;
using CustomPipelines = std::unordered_map<std::string, CustomPipeline>;
bool pipelineNeedsUpdate(Modes mode, std::string customFile = std::string()) const;
const gpu::PipelinePointer& getPipeline(Modes mode, std::string customFile = std::string());
std::string getShaderSourceCode(Modes mode, std::string customFile = std::string());
bool pipelineNeedsUpdate(Mode mode, std::string customFile = std::string()) const;
const gpu::PipelinePointer& getPipeline(Mode mode, std::string customFile = std::string());
std::string getShaderSourceCode(Mode mode, std::string customFile = std::string());
StandardPipelines _pipelines;
CustomPipelines _customPipelines;

View file

@ -162,7 +162,7 @@ void DeferredLightingEffect::prepare(RenderArgs* args) {
}
void DeferredLightingEffect::render(const render::RenderContextPointer& renderContext) {
auto args = renderContext->getArgs();
auto args = renderContext->args;
gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
// Allocate the parameters buffer used by all the deferred shaders
@ -188,14 +188,14 @@ void DeferredLightingEffect::render(const render::RenderContextPointer& renderCo
batch.setViewportTransform(args->_viewport);
batch.setStateScissorRect(args->_viewport);
// BInd the G-Buffer surfaces
// Bind the G-Buffer surfaces
batch.setResourceTexture(DEFERRED_BUFFER_COLOR_UNIT, framebufferCache->getDeferredColorTexture());
batch.setResourceTexture(DEFERRED_BUFFER_NORMAL_UNIT, framebufferCache->getDeferredNormalTexture());
batch.setResourceTexture(DEFERRED_BUFFER_EMISSIVE_UNIT, framebufferCache->getDeferredSpecularTexture());
batch.setResourceTexture(DEFERRED_BUFFER_DEPTH_UNIT, framebufferCache->getPrimaryDepthTexture());
// need to assign the white texture if ao is off
if (renderContext->getOcclusionStatus()) {
if (_ambientOcclusionEnabled) {
batch.setResourceTexture(DEFERRED_BUFFER_OBSCURANCE_UNIT, framebufferCache->getOcclusionTexture());
} else {
batch.setResourceTexture(DEFERRED_BUFFER_OBSCURANCE_UNIT, textureCache->getWhiteTexture());
@ -313,12 +313,12 @@ void DeferredLightingEffect::render(const render::RenderContextPointer& renderCo
{
bool useSkyboxCubemap = (_skybox) && (_skybox->getCubemap());
auto& program = _shadowMapStatus ? _directionalLightShadow : _directionalLight;
LightLocationsPtr locations = _shadowMapStatus ? _directionalLightShadowLocations : _directionalLightLocations;
auto& program = _shadowMapEnabled ? _directionalLightShadow : _directionalLight;
LightLocationsPtr locations = _shadowMapEnabled ? _directionalLightShadowLocations : _directionalLightLocations;
// Setup the global directional pass pipeline
{
if (_shadowMapStatus) {
if (_shadowMapEnabled) {
if (useSkyboxCubemap) {
program = _directionalSkyboxLightShadow;
locations = _directionalSkyboxLightShadowLocations;

View file

@ -54,14 +54,17 @@ public:
void setGlobalSkybox(const model::SkyboxPointer& skybox);
const LightStage& getLightStage() { return _lightStage; }
void setShadowMapStatus(bool enable) { _shadowMapStatus = enable; };
void setShadowMapEnabled(bool enable) { _shadowMapEnabled = enable; };
void setAmbientOcclusionEnabled(bool enable) { _ambientOcclusionEnabled = enable; }
private:
LightStage _lightStage;
bool _shadowMapStatus{ false };
DeferredLightingEffect() = default;
LightStage _lightStage;
bool _shadowMapEnabled{ false };
bool _ambientOcclusionEnabled{ false };
model::MeshPointer _spotLightMesh;
model::MeshPointer getSpotLightMesh();

View file

@ -61,9 +61,10 @@ const gpu::PipelinePointer& HitEffect::getHitEffectPipeline() {
}
void HitEffect::run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext) {
assert(renderContext->getArgs());
assert(renderContext->getArgs()->_viewFrustum);
RenderArgs* args = renderContext->getArgs();
assert(renderContext->args);
assert(renderContext->args->_viewFrustum);
RenderArgs* args = renderContext->args;
gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
glm::mat4 projMat;

View file

@ -11,13 +11,21 @@
#include <render/DrawTask.h>
class HitEffectConfig : public render::Job::Config {
Q_OBJECT
Q_PROPERTY(bool enabled MEMBER enabled)
public:
HitEffectConfig() : render::Job::Config(false) {}
};
class HitEffect {
public:
using Config = HitEffectConfig;
using JobModel = render::Job::Model<HitEffect, Config>;
HitEffect();
void configure(const Config& config) {}
void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext);
using JobModel = render::Task::Job::Model<HitEffect>;
const gpu::PipelinePointer& getHitEffectPipeline();

View file

@ -60,18 +60,28 @@ using namespace render;
void initDeferredPipelines(render::ShapePlumber& plumber);
void PrepareDeferred::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
DependencyManager::get<DeferredLightingEffect>()->prepare(renderContext->getArgs());
DependencyManager::get<DeferredLightingEffect>()->prepare(renderContext->args);
}
void RenderDeferred::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
DependencyManager::get<DeferredLightingEffect>()->render(renderContext);
}
void ToneMappingDeferred::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
_toneMappingEffect.render(renderContext->getArgs());
void ToneMappingDeferred::configure(const Config& config) {
if (config.exposure >= 0.0f) {
_toneMappingEffect.setExposure(config.exposure);
}
if (config.curve >= 0) {
_toneMappingEffect.setToneCurve((ToneMappingEffect::ToneCurve)config.curve);
}
}
RenderDeferredTask::RenderDeferredTask(CullFunctor cullFunctor) : Task() {
void ToneMappingDeferred::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
_toneMappingEffect.render(renderContext->args);
}
RenderDeferredTask::RenderDeferredTask(CullFunctor cullFunctor) {
cullFunctor = cullFunctor ? cullFunctor : [](const RenderArgs*, const AABox&){ return true; };
// Prepare the ShapePipelines
@ -79,19 +89,13 @@ RenderDeferredTask::RenderDeferredTask(CullFunctor cullFunctor) : Task() {
initDeferredPipelines(*shapePlumber);
// CPU: Fetch the renderOpaques
auto fetchedOpaques = addJob<FetchItems>("FetchOpaque", FetchItems([](const RenderContextPointer& context, int count) {
context->getItemsConfig().opaque.numFeed = count;
}));
auto fetchedOpaques = addJob<FetchItems>("FetchOpaque");
auto culledOpaques = addJob<CullItems<RenderDetails::OPAQUE_ITEM>>("CullOpaque", fetchedOpaques, cullFunctor);
auto opaques = addJob<DepthSortItems>("DepthSortOpaque", culledOpaques);
// CPU only, create the list of renderedTransparents items
auto fetchedTransparents = addJob<FetchItems>("FetchTransparent", FetchItems(
ItemFilter::Builder::transparentShape().withoutLayered(),
[](const RenderContextPointer& context, int count) {
context->getItemsConfig().transparent.numFeed = count;
}
));
ItemFilter::Builder::transparentShape().withoutLayered()));
auto culledTransparents = addJob<CullItems<RenderDetails::TRANSLUCENT_ITEM>>("CullTransparent", fetchedTransparents, cullFunctor);
auto transparents = addJob<DepthSortItems>("DepthSortTransparent", culledTransparents, DepthSortItems(false));
@ -99,7 +103,7 @@ RenderDeferredTask::RenderDeferredTask(CullFunctor cullFunctor) : Task() {
addJob<PrepareDeferred>("PrepareDeferred");
// Render opaque objects in DeferredBuffer
addJob<DrawOpaqueDeferred>("DrawOpaqueDeferred", opaques, shapePlumber);
addJob<DrawDeferred>("DrawOpaqueDeferred", opaques, shapePlumber);
// Once opaque is all rendered create stencil background
addJob<DrawStencilDeferred>("DrawOpaqueStencil");
@ -109,8 +113,6 @@ RenderDeferredTask::RenderDeferredTask(CullFunctor cullFunctor) : Task() {
// AO job
addJob<AmbientOcclusionEffect>("AmbientOcclusion");
_jobs.back().setEnabled(false);
_occlusionJobIndex = (int)_jobs.size() - 1;
// Draw Lights just add the lights to the current list of lights to deal with. NOt really gpu job for now.
addJob<DrawLight>("DrawLight", cullFunctor);
@ -120,20 +122,15 @@ RenderDeferredTask::RenderDeferredTask(CullFunctor cullFunctor) : Task() {
// AA job to be revisited
addJob<Antialiasing>("Antialiasing");
_antialiasingJobIndex = (int)_jobs.size() - 1;
enableJob(_antialiasingJobIndex, false);
// Render transparent objects forward in LigthingBuffer
addJob<DrawTransparentDeferred>("DrawTransparentDeferred", transparents, shapePlumber);
// Render transparent objects forward in LightingBuffer
addJob<DrawDeferred>("DrawTransparentDeferred", transparents, shapePlumber);
// Lighting Buffer ready for tone mapping
addJob<ToneMappingDeferred>("ToneMapping");
_toneMappingJobIndex = (int)_jobs.size() - 1;
// Debugging Deferred buffer job
addJob<DebugDeferredBuffer>("DebugDeferredBuffer");
_drawDebugDeferredBufferIndex = (int)_jobs.size() - 1;
enableJob(_drawDebugDeferredBufferIndex, false);
// Status icon rendering job
{
@ -141,15 +138,11 @@ RenderDeferredTask::RenderDeferredTask(CullFunctor cullFunctor) : Task() {
auto iconMapPath = PathUtils::resourcesPath() + "icons/statusIconAtlas.svg";
auto statusIconMap = DependencyManager::get<TextureCache>()->getImageTexture(iconMapPath);
addJob<DrawStatus>("DrawStatus", opaques, DrawStatus(statusIconMap));
_drawStatusJobIndex = (int)_jobs.size() - 1;
enableJob(_drawStatusJobIndex, false);
}
addJob<DrawOverlay3D>("DrawOverlay3D", shapePlumber);
addJob<HitEffect>("HitEffect");
_drawHitEffectJobIndex = (int)_jobs.size() -1;
enableJob(_drawHitEffectJobIndex, false);
addJob<Blit>("Blit");
}
@ -163,62 +156,28 @@ void RenderDeferredTask::run(const SceneContextPointer& sceneContext, const Rend
// Is it possible that we render without a viewFrustum ?
if (!(renderContext->getArgs() && renderContext->getArgs()->_viewFrustum)) {
if (!(renderContext->args && renderContext->args->_viewFrustum)) {
return;
}
setDrawDebugDeferredBuffer(renderContext->_deferredDebugMode);
setDrawItemStatus(renderContext->getDrawStatus());
setDrawHitEffect(renderContext->getDrawHitEffect());
// TODO: turn on/off AO through menu item
setOcclusionStatus(renderContext->getOcclusionStatus());
if (_occlusionJobIndex >= 0) {
_jobs[_occlusionJobIndex].edit<AmbientOcclusionEffect>().setResolutionLevel(renderContext->getAmbientOcclusion().resolutionLevel);
_jobs[_occlusionJobIndex].edit<AmbientOcclusionEffect>().setRadius(renderContext->getAmbientOcclusion().radius);
_jobs[_occlusionJobIndex].edit<AmbientOcclusionEffect>().setLevel(renderContext->getAmbientOcclusion().level);
_jobs[_occlusionJobIndex].edit<AmbientOcclusionEffect>().setNumSamples(renderContext->getAmbientOcclusion().numSamples);
_jobs[_occlusionJobIndex].edit<AmbientOcclusionEffect>().setNumSpiralTurns(renderContext->getAmbientOcclusion().numSpiralTurns);
_jobs[_occlusionJobIndex].edit<AmbientOcclusionEffect>().setDithering(renderContext->getAmbientOcclusion().ditheringEnabled);
_jobs[_occlusionJobIndex].edit<AmbientOcclusionEffect>().setFalloffBias(renderContext->getAmbientOcclusion().falloffBias);
_jobs[_occlusionJobIndex].edit<AmbientOcclusionEffect>().setEdgeSharpness(renderContext->getAmbientOcclusion().edgeSharpness);
_jobs[_occlusionJobIndex].edit<AmbientOcclusionEffect>().setBlurRadius(renderContext->getAmbientOcclusion().blurRadius);
_jobs[_occlusionJobIndex].edit<AmbientOcclusionEffect>().setBlurDeviation(renderContext->getAmbientOcclusion().blurDeviation);
}
setAntialiasingStatus(renderContext->getFxaaStatus());
setToneMappingExposure(renderContext->getTone().exposure);
setToneMappingToneCurve(renderContext->getTone().toneCurve);
// TODO: Allow runtime manipulation of culling ShouldRenderFunctor
// TODO: For now, lighting is controlled through a singleton, so it is distinct
DependencyManager::get<DeferredLightingEffect>()->setShadowMapStatus(renderContext->getShadowMapStatus());
renderContext->getArgs()->_context->syncCache();
for (auto job : _jobs) {
job.run(sceneContext, renderContext);
}
if (_occlusionJobIndex >= 0 && renderContext->getOcclusionStatus()) {
renderContext->getAmbientOcclusion().gpuTime = _jobs[_occlusionJobIndex].edit<AmbientOcclusionEffect>().getGPUTime();
} else {
renderContext->getAmbientOcclusion().gpuTime = 0.0;
}
};
void DrawOpaqueDeferred::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems) {
assert(renderContext->getArgs());
assert(renderContext->getArgs()->_viewFrustum);
void DrawDeferred::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems) {
assert(renderContext->args);
assert(renderContext->args->_viewFrustum);
RenderArgs* args = renderContext->getArgs();
auto config = std::static_pointer_cast<Config>(renderContext->jobConfig);
RenderArgs* args = renderContext->args;
gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
batch.setViewportTransform(args->_viewport);
batch.setStateScissorRect(args->_viewport);
args->_batch = &batch;
auto& opaque = renderContext->getItemsConfig().opaque;
opaque.numDrawn = (int)inItems.size();
config->numDrawn = (int)inItems.size();
glm::mat4 projMat;
Transform viewMat;
@ -228,33 +187,7 @@ void DrawOpaqueDeferred::run(const SceneContextPointer& sceneContext, const Rend
batch.setProjectionTransform(projMat);
batch.setViewTransform(viewMat);
renderShapes(sceneContext, renderContext, _shapePlumber, inItems, opaque.maxDrawn);
args->_batch = nullptr;
});
}
void DrawTransparentDeferred::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems) {
assert(renderContext->getArgs());
assert(renderContext->getArgs()->_viewFrustum);
RenderArgs* args = renderContext->getArgs();
gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
batch.setViewportTransform(args->_viewport);
batch.setStateScissorRect(args->_viewport);
args->_batch = &batch;
auto& transparent = renderContext->getItemsConfig().transparent;
transparent.numDrawn = (int)inItems.size();
glm::mat4 projMat;
Transform viewMat;
args->_viewFrustum->evalProjectionMatrix(projMat);
args->_viewFrustum->evalViewTransform(viewMat);
batch.setProjectionTransform(projMat);
batch.setViewTransform(viewMat);
renderShapes(sceneContext, renderContext, _shapePlumber, inItems, transparent.maxDrawn);
renderShapes(sceneContext, renderContext, _shapePlumber, inItems, _maxDrawn);
args->_batch = nullptr;
});
}
@ -278,13 +211,14 @@ const gpu::PipelinePointer& DrawOverlay3D::getOpaquePipeline() {
}
void DrawOverlay3D::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
assert(renderContext->getArgs());
assert(renderContext->getArgs()->_viewFrustum);
assert(renderContext->args);
assert(renderContext->args->_viewFrustum);
// render backgrounds
auto& scene = sceneContext->_scene;
auto& items = scene->getMasterBucket().at(ItemFilter::Builder::opaqueShape().withLayered());
auto config = std::static_pointer_cast<Config>(renderContext->jobConfig);
ItemIDsBounds inItems;
inItems.reserve(items.size());
@ -294,12 +228,11 @@ void DrawOverlay3D::run(const SceneContextPointer& sceneContext, const RenderCon
inItems.emplace_back(id);
}
}
auto& overlay3D = renderContext->getItemsConfig().overlay3D;
overlay3D.numFeed = (int)inItems.size();
overlay3D.numDrawn = (int)inItems.size();
config->numItems = (int)inItems.size();
config->numDrawn = (int)inItems.size();
if (!inItems.empty()) {
RenderArgs* args = renderContext->getArgs();
RenderArgs* args = renderContext->args;
// Clear the framebuffer without stereo
// Needs to be distinct from the other batch because using the clear call
@ -328,7 +261,7 @@ void DrawOverlay3D::run(const SceneContextPointer& sceneContext, const RenderCon
batch.setPipeline(getOpaquePipeline());
batch.setResourceTexture(0, args->_whiteTexture);
renderShapes(sceneContext, renderContext, _shapePlumber, inItems, renderContext->getItemsConfig().overlay3D.maxDrawn);
renderShapes(sceneContext, renderContext, _shapePlumber, inItems, _maxDrawn);
});
args->_batch = nullptr;
args->_whiteTexture.reset();
@ -357,11 +290,11 @@ const gpu::PipelinePointer& DrawStencilDeferred::getOpaquePipeline() {
}
void DrawStencilDeferred::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
assert(renderContext->getArgs());
assert(renderContext->getArgs()->_viewFrustum);
assert(renderContext->args);
assert(renderContext->args->_viewFrustum);
// from the touched pixel generate the stencil buffer
RenderArgs* args = renderContext->getArgs();
RenderArgs* args = renderContext->args;
doInBatch(args->_context, [&](gpu::Batch& batch) {
args->_batch = &batch;
@ -383,8 +316,8 @@ void DrawStencilDeferred::run(const SceneContextPointer& sceneContext, const Ren
}
void DrawBackgroundDeferred::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
assert(renderContext->getArgs());
assert(renderContext->getArgs()->_viewFrustum);
assert(renderContext->args);
assert(renderContext->args->_viewFrustum);
// render backgrounds
auto& scene = sceneContext->_scene;
@ -396,7 +329,7 @@ void DrawBackgroundDeferred::run(const SceneContextPointer& sceneContext, const
for (auto id : items) {
inItems.emplace_back(id);
}
RenderArgs* args = renderContext->getArgs();
RenderArgs* args = renderContext->args;
doInBatch(args->_context, [&](gpu::Batch& batch) {
args->_batch = &batch;
@ -423,10 +356,10 @@ void DrawBackgroundDeferred::run(const SceneContextPointer& sceneContext, const
}
void Blit::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
assert(renderContext->getArgs());
assert(renderContext->getArgs()->_context);
assert(renderContext->args);
assert(renderContext->args->_context);
RenderArgs* renderArgs = renderContext->getArgs();
RenderArgs* renderArgs = renderContext->args;
auto blitFbo = renderArgs->_blitFramebuffer;
if (!blitFbo) {
@ -493,34 +426,6 @@ void Blit::run(const SceneContextPointer& sceneContext, const RenderContextPoint
});
}
void RenderDeferredTask::setToneMappingExposure(float exposure) {
if (_toneMappingJobIndex >= 0) {
_jobs[_toneMappingJobIndex].edit<ToneMappingDeferred>()._toneMappingEffect.setExposure(exposure);
}
}
float RenderDeferredTask::getToneMappingExposure() const {
if (_toneMappingJobIndex >= 0) {
return _jobs[_toneMappingJobIndex].get<ToneMappingDeferred>()._toneMappingEffect.getExposure();
} else {
return 0.0f;
}
}
void RenderDeferredTask::setToneMappingToneCurve(int toneCurve) {
if (_toneMappingJobIndex >= 0) {
_jobs[_toneMappingJobIndex].edit<ToneMappingDeferred>()._toneMappingEffect.setToneCurve((ToneMappingEffect::ToneCurve)toneCurve);
}
}
int RenderDeferredTask::getToneMappingToneCurve() const {
if (_toneMappingJobIndex >= 0) {
return _jobs[_toneMappingJobIndex].get<ToneMappingDeferred>()._toneMappingEffect.getToneCurve();
} else {
return 0.0f;
}
}
void pipelineBatchSetter(const ShapePipeline& pipeline, gpu::Batch& batch) {
if (pipeline.locations->normalFittingMapUnit > -1) {
batch.setResourceTexture(pipeline.locations->normalFittingMapUnit,

View file

@ -22,14 +22,14 @@ class SetupDeferred {
public:
void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext);
using JobModel = render::Task::Job::Model<SetupDeferred>;
using JobModel = render::Job::Model<SetupDeferred>;
};
class PrepareDeferred {
public:
void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext);
using JobModel = render::Task::Job::Model<PrepareDeferred>;
using JobModel = render::Job::Model<PrepareDeferred>;
};
@ -37,38 +37,61 @@ class RenderDeferred {
public:
void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext);
using JobModel = render::Task::Job::Model<RenderDeferred>;
using JobModel = render::Job::Model<RenderDeferred>;
};
class ToneMappingConfig : public render::Job::Config {
Q_OBJECT
Q_PROPERTY(bool enabled MEMBER enabled)
Q_PROPERTY(float exposure MEMBER exposure NOTIFY dirty);
Q_PROPERTY(int curve MEMBER curve NOTIFY dirty);
public:
ToneMappingConfig() : render::Job::Config(true) {}
float exposure{ 0.0f };
int curve{ 3 };
signals:
void dirty();
};
class ToneMappingDeferred {
public:
using Config = ToneMappingConfig;
using JobModel = render::Job::Model<ToneMappingDeferred, Config>;
void configure(const Config& config);
void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext);
ToneMappingEffect _toneMappingEffect;
using JobModel = render::Task::Job::Model<ToneMappingDeferred>;
};
class DrawOpaqueDeferred {
class DrawConfig : public render::Job::Config {
Q_OBJECT
Q_PROPERTY(int numDrawn READ getNumDrawn)
Q_PROPERTY(int maxDrawn MEMBER maxDrawn NOTIFY dirty)
public:
DrawOpaqueDeferred(render::ShapePlumberPointer shapePlumber) : _shapePlumber{ shapePlumber } {}
void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, const render::ItemIDsBounds& inItems);
int getNumDrawn() { return numDrawn; }
using JobModel = render::Task::Job::ModelI<DrawOpaqueDeferred, render::ItemIDsBounds>;
protected:
render::ShapePlumberPointer _shapePlumber;
};
class DrawTransparentDeferred {
public:
DrawTransparentDeferred(render::ShapePlumberPointer shapePlumber) : _shapePlumber{ shapePlumber } {}
void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, const render::ItemIDsBounds& inItems);
using JobModel = render::Task::Job::ModelI<DrawTransparentDeferred, render::ItemIDsBounds>;
int numDrawn{ 0 };
int maxDrawn{ -1 };
signals:
void dirty();
};
class DrawDeferred {
public:
using Config = DrawConfig;
using JobModel = render::Job::ModelI<DrawDeferred, render::ItemIDsBounds, Config>;
DrawDeferred(render::ShapePlumberPointer shapePlumber) : _shapePlumber{ shapePlumber } {}
void configure(const Config& config) { _maxDrawn = config.maxDrawn; }
void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, const render::ItemIDsBounds& inItems);
protected:
render::ShapePlumberPointer _shapePlumber;
int _maxDrawn; // initialized by Config
};
class DrawStencilDeferred {
@ -77,7 +100,7 @@ public:
void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext);
using JobModel = render::Task::Job::Model<DrawStencilDeferred>;
using JobModel = render::Job::Model<DrawStencilDeferred>;
protected:
static gpu::PipelinePointer _opaquePipeline; //lazy evaluation hence mutable
@ -87,64 +110,57 @@ class DrawBackgroundDeferred {
public:
void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext);
using JobModel = render::Task::Job::Model<DrawBackgroundDeferred>;
using JobModel = render::Job::Model<DrawBackgroundDeferred>;
};
class DrawOverlay3DConfig : public render::Job::Config {
Q_OBJECT
Q_PROPERTY(int numItems READ getNumItems)
Q_PROPERTY(int numDrawn READ getNumDrawn)
Q_PROPERTY(int maxDrawn MEMBER maxDrawn NOTIFY dirty)
public:
int getNumItems() { return numItems; }
int getNumDrawn() { return numDrawn; }
int numItems{ 0 };
int numDrawn{ 0 };
int maxDrawn{ -1 };
signals:
void dirty();
};
class DrawOverlay3D {
public:
DrawOverlay3D(render::ShapePlumberPointer shapePlumber) : _shapePlumber{ shapePlumber } {}
static const gpu::PipelinePointer& getOpaquePipeline();
using Config = DrawOverlay3DConfig;
using JobModel = render::Job::Model<DrawOverlay3D, Config>;
DrawOverlay3D(render::ShapePlumberPointer shapePlumber) : _shapePlumber{ shapePlumber } {}
void configure(const Config& config) { _maxDrawn = config.maxDrawn; }
void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext);
using JobModel = render::Task::Job::Model<DrawOverlay3D>;
static const gpu::PipelinePointer& getOpaquePipeline();
protected:
static gpu::PipelinePointer _opaquePipeline; //lazy evaluation hence mutable
render::ShapePlumberPointer _shapePlumber;
int _maxDrawn; // initialized by Config
};
class Blit {
public:
void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext);
using JobModel = render::Task::Job::Model<Blit>;
using JobModel = render::Job::Model<Blit>;
};
class RenderDeferredTask : public render::Task {
public:
RenderDeferredTask(render::CullFunctor cullFunctor);
void setDrawDebugDeferredBuffer(int draw) { enableJob(_drawDebugDeferredBufferIndex, draw >= 0); }
bool doDrawDebugDeferredBuffer() const { return getEnableJob(_drawDebugDeferredBufferIndex); }
void setDrawItemStatus(int draw) { enableJob(_drawStatusJobIndex, draw > 0); }
bool doDrawItemStatus() const { return getEnableJob(_drawStatusJobIndex); }
void setDrawHitEffect(bool draw) { enableJob(_drawHitEffectJobIndex, draw); }
bool doDrawHitEffect() const { return getEnableJob(_drawHitEffectJobIndex); }
void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext);
void setOcclusionStatus(bool draw) { enableJob(_occlusionJobIndex, draw); }
bool doOcclusionStatus() const { return getEnableJob(_occlusionJobIndex); }
void setAntialiasingStatus(bool draw) { enableJob(_antialiasingJobIndex, draw); }
bool doAntialiasingStatus() const { return getEnableJob(_antialiasingJobIndex); }
void setToneMappingExposure(float exposure);
float getToneMappingExposure() const;
void setToneMappingToneCurve(int toneCurve);
int getToneMappingToneCurve() const;
virtual void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext);
protected:
int _drawDebugDeferredBufferIndex;
int _drawStatusJobIndex;
int _drawHitEffectJobIndex;
int _occlusionJobIndex;
int _antialiasingJobIndex;
int _toneMappingJobIndex;
using JobModel = Model<RenderDeferredTask>;
};
#endif // hifi_RenderDeferredTask_h

View file

@ -1,56 +0,0 @@
//
// RenderScriptingInterface.cpp
// libraries/render-utils
//
// Created by Zach Pomerantz on 12/16/15.
// Copyright 2015 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 "RenderScriptingInterface.h"
RenderScriptingInterface::RenderScriptingInterface() {};
void RenderScripting::Tone::setCurve(const QString& curve) {
if (curve == QString("None")) {
toneCurve = 0;
} else if (curve == QString("Gamma22")) {
toneCurve = 1;
} else if (curve == QString("Reinhard")) {
toneCurve = 2;
} else if (curve == QString("Filmic")) {
toneCurve = 3;
}
}
QString RenderScripting::Tone::getCurve() const {
switch (toneCurve) {
case 0:
return QString("None");
case 1:
return QString("Gamma22");
case 2:
return QString("Reinhard");
case 3:
return QString("Filmic");
default:
return QString("Filmic");
};
}
render::RenderContext RenderScriptingInterface::getRenderContext() {
render::RenderContext::ItemsConfig items{ *_opaque, *_transparent, *_overlay3D };
return render::RenderContext{ items, *_tone, *_ambientOcclusion, _drawStatus, _drawHitEffect, _deferredDebugSize, _deferredDebugMode };
}
void RenderScriptingInterface::setItemCounts(const render::RenderContext::ItemsConfig& items) {
_opaque->setCounts(items.opaque);
_transparent->setCounts(items.transparent);
_overlay3D->setCounts(items.overlay3D);
}
void RenderScriptingInterface::setJobGPUTimes(double aoTime) {
_ambientOcclusion->gpuTime = aoTime;
}

View file

@ -1,140 +0,0 @@
//
// RenderScriptingInterface.h
// libraries/render-utils
//
// Created by Zach Pomerantz on 12/16/15.
// 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
//
#ifndef hifi_RenderScriptingInterface_h
#define hifi_RenderScriptingInterface_h
#include <qscriptengine.h> // QObject
#include <DependencyManager.h> // Dependency
#include "render/Engine.h"
namespace RenderScripting {
using State = render::RenderContext::ItemsConfig::State;
using Counter = render::RenderContext::ItemsConfig::Counter;
class ItemCounter : public QObject, public Counter {
Q_OBJECT
public:
Q_PROPERTY(int numFeed READ getNumFeed)
Q_PROPERTY(int numDrawn READ getNumDrawn)
Q_PROPERTY(int maxDrawn MEMBER maxDrawn)
protected:
int getNumFeed() const { return numFeed; }
int getNumDrawn() const { return numDrawn; }
};
using ItemCounterPointer = std::unique_ptr<ItemCounter>;
class ItemState : public QObject, public State {
Q_OBJECT
public:
Q_PROPERTY(bool render MEMBER render)
Q_PROPERTY(bool cull MEMBER cull)
Q_PROPERTY(bool sort MEMBER sort)
Q_PROPERTY(int numFeed READ getNumFeed)
Q_PROPERTY(int numDrawn READ getNumDrawn)
Q_PROPERTY(int maxDrawn MEMBER maxDrawn)
protected:
int getNumFeed() const { return numFeed; }
int getNumDrawn() const { return numDrawn; }
};
using ItemStatePointer = std::unique_ptr<ItemState>;
class Tone : public QObject, public render::RenderContext::Tone {
Q_OBJECT
public:
Q_PROPERTY(float exposure MEMBER exposure)
Q_PROPERTY(QString curve READ getCurve WRITE setCurve)
QString getCurve() const;
int getCurveValue() const { return toneCurve; }
void setCurve(const QString& curve);
};
using TonePointer = std::unique_ptr<Tone>;
class AmbientOcclusion : public QObject, public render::RenderContext::AmbientOcclusion {
Q_OBJECT
public:
Q_PROPERTY(int resolutionLevel MEMBER resolutionLevel)
Q_PROPERTY(float radius MEMBER radius)
Q_PROPERTY(float level MEMBER level)
Q_PROPERTY(int numSamples MEMBER numSamples)
Q_PROPERTY(float numSpiralTurns MEMBER numSpiralTurns)
Q_PROPERTY(bool ditheringEnabled MEMBER ditheringEnabled)
Q_PROPERTY(float falloffBias MEMBER falloffBias)
Q_PROPERTY(float edgeSharpness MEMBER edgeSharpness)
Q_PROPERTY(int blurRadius MEMBER blurRadius)
Q_PROPERTY(float blurDeviation MEMBER blurDeviation)
Q_PROPERTY(double gpuTime MEMBER gpuTime)
};
using AmbientOcclusionPointer = std::unique_ptr<AmbientOcclusion>;
};
class RenderScriptingInterface : public QObject, public Dependency {
Q_OBJECT
SINGLETON_DEPENDENCY
public:
Q_PROPERTY(RenderScripting::ItemState* opaque READ getOpaque)
Q_PROPERTY(RenderScripting::ItemState* transparent READ getTransparent)
Q_PROPERTY(RenderScripting::ItemCounter* overlay3D READ getOverlay3D)
Q_PROPERTY(RenderScripting::Tone* tone READ getTone)
Q_PROPERTY(RenderScripting::AmbientOcclusion* ambientOcclusion READ getAmbientOcclusion)
Q_PROPERTY(int displayItemStatus MEMBER _drawStatus)
Q_PROPERTY(bool displayHitEffect MEMBER _drawHitEffect)
Q_PROPERTY(int deferredDebugMode MEMBER _deferredDebugMode)
Q_PROPERTY(glm::vec4 deferredDebugSize MEMBER _deferredDebugSize)
render::RenderContext getRenderContext();
void setItemCounts(const render::RenderContext::ItemsConfig& items);
// FIXME: It is ugly, we need a cleaner solution
void setJobGPUTimes(double aoTime);
protected:
RenderScriptingInterface();
~RenderScriptingInterface() {};
RenderScripting::ItemState* getOpaque() const { return _opaque.get(); }
RenderScripting::ItemState* getTransparent() const { return _transparent.get(); }
RenderScripting::ItemCounter* getOverlay3D() const { return _overlay3D.get(); }
RenderScripting::Tone* getTone() const { return _tone.get(); }
RenderScripting::AmbientOcclusion* getAmbientOcclusion() const { return _ambientOcclusion.get(); }
RenderScripting::ItemStatePointer _opaque = RenderScripting::ItemStatePointer{new RenderScripting::ItemState{}};
RenderScripting::ItemStatePointer _transparent = RenderScripting::ItemStatePointer{new RenderScripting::ItemState{}};
RenderScripting::ItemCounterPointer _overlay3D = RenderScripting::ItemCounterPointer{new RenderScripting::ItemCounter{}};
RenderScripting::TonePointer _tone = RenderScripting::TonePointer{ new RenderScripting::Tone{} };
RenderScripting::AmbientOcclusionPointer _ambientOcclusion = RenderScripting::AmbientOcclusionPointer{ new RenderScripting::AmbientOcclusion{} };
// Options
int _drawStatus = 0;
bool _drawHitEffect = false;
// Debugging
int _deferredDebugMode = -1;
glm::vec4 _deferredDebugSize { 0.0f, -1.0f, 1.0f, 1.0f };
};
#endif // hifi_RenderScriptingInterface_h

View file

@ -29,15 +29,15 @@ using namespace render;
void RenderShadowMap::run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext,
const render::ShapesIDsBounds& inShapes) {
assert(renderContext->getArgs());
assert(renderContext->getArgs()->_viewFrustum);
assert(renderContext->args);
assert(renderContext->args->_viewFrustum);
const auto& lightStage = DependencyManager::get<DeferredLightingEffect>()->getLightStage();
const auto globalLight = lightStage.lights[0];
const auto& shadow = globalLight->shadow;
const auto& fbo = shadow.framebuffer;
RenderArgs* args = renderContext->getArgs();
RenderArgs* args = renderContext->args;
gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
args->_batch = &batch;
@ -78,7 +78,8 @@ void RenderShadowMap::run(const render::SceneContextPointer& sceneContext, const
});
}
RenderShadowTask::RenderShadowTask(CullFunctor cullFunctor) : Task() {
// The shadow task *must* use this base ctor to initialize with its own Config, see Task.h
RenderShadowTask::RenderShadowTask(CullFunctor cullFunctor) : Task(std::make_shared<Config>()) {
cullFunctor = cullFunctor ? cullFunctor : [](const RenderArgs*, const AABox&){ return true; };
// Prepare the ShapePipeline
@ -119,14 +120,15 @@ RenderShadowTask::RenderShadowTask(CullFunctor cullFunctor) : Task() {
addJob<RenderShadowMap>("RenderShadowMap", shadowShapes, shapePlumber);
}
void RenderShadowTask::configure(const Config& configuration) {
DependencyManager::get<DeferredLightingEffect>()->setShadowMapEnabled(configuration.enabled);
// This is a task, so must still propogate configure() to its Jobs
Task::configure(configuration);
}
void RenderShadowTask::run(const SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext) {
assert(sceneContext);
RenderArgs* args = renderContext->getArgs();
// This feature is in a debugging stage - it must be turned on explicitly
if (!renderContext->getShadowMapStatus()) {
return;
}
RenderArgs* args = renderContext->args;
// sanity checks
if (!sceneContext->_scene || !args) {

View file

@ -21,19 +21,34 @@ class ViewFrustum;
class RenderShadowMap {
public:
using JobModel = render::Job::ModelI<RenderShadowMap, render::ShapesIDsBounds>;
RenderShadowMap(render::ShapePlumberPointer shapePlumber) : _shapePlumber{ shapePlumber } {}
void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext,
const render::ShapesIDsBounds& inShapes);
using JobModel = render::Task::Job::ModelI<RenderShadowMap, render::ShapesIDsBounds>;
protected:
render::ShapePlumberPointer _shapePlumber;
};
class RenderShadowTaskConfig : public render::Task::Config {
Q_OBJECT
Q_PROPERTY(bool enabled MEMBER enabled NOTIFY dirty)
public:
RenderShadowTaskConfig() : render::Task::Config(false) {}
signals:
void dirty();
};
class RenderShadowTask : public render::Task {
public:
using Config = RenderShadowTaskConfig;
using JobModel = Model<RenderShadowTask, Config>;
RenderShadowTask(render::CullFunctor shouldRender);
void configure(const Config& configuration);
void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext);
};

View file

@ -1,31 +0,0 @@
//
// Context.cpp
// render/src/render
//
// Created by Zach Pomerantz on 1/6/2015.
// Copyright 2015 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 "Context.h"
using namespace render;
RenderContext::RenderContext(ItemsConfig items, Tone tone, AmbientOcclusion ao, int drawStatus, bool drawHitEffect, glm::vec4 deferredDebugSize, int deferredDebugMode)
: _deferredDebugMode{ deferredDebugMode }, _deferredDebugSize{ deferredDebugSize },
_args{ nullptr },
_drawStatus{ drawStatus }, _drawHitEffect{ drawHitEffect },
_items{ items }, _tone{ tone }, _ambientOcclusion{ ao } {}
void RenderContext::setOptions(bool occlusion, bool fxaa, bool showOwned, bool shadowMap) {
_occlusionStatus = occlusion;
_fxaaStatus = fxaa;
_shadowMapStatus = shadowMap;
if (showOwned) {
_drawStatus |= render::showNetworkStatusFlag;
}
};

View file

@ -24,104 +24,14 @@ public:
};
using SceneContextPointer = std::shared_ptr<SceneContext>;
// see examples/utilities/tools/renderEngineDebug.js
const int showDisplayStatusFlag = 1;
const int showNetworkStatusFlag = 2;
class JobConfig;
class RenderContext {
public:
class ItemsConfig {
public:
class Counter {
public:
Counter() {}
Counter(const Counter& counter) : maxDrawn { counter.maxDrawn } {}
void setCounts(const Counter& counter) {
numFeed = counter.numFeed;
numDrawn = counter.numDrawn;
};
int numFeed { 0 };
int numDrawn { 0 };
int maxDrawn { -1 };
};
class State : public Counter {
public:
bool render { true };
bool cull { true };
bool sort { true };
Counter counter{};
};
ItemsConfig(State opaqueState, State transparentState, Counter overlay3DCounter)
: opaque{ opaqueState }, transparent{ transparentState }, overlay3D{ overlay3DCounter } {}
ItemsConfig() : ItemsConfig{ {}, {}, {} } {}
// TODO: If member count increases, store counters in a map instead of multiple members
State opaque{};
State transparent{};
Counter overlay3D{};
};
class Tone {
public:
int toneCurve = 1; // Means just Gamma 2.2 correction
float exposure = 0.0;
};
class AmbientOcclusion {
public:
int resolutionLevel { 1 };
float radius { 0.5f }; // radius in meters of the AO effect
float level { 0.5f }; // Level of the obscrance value
int numSamples { 11 }; // Num Samples per pixel
float numSpiralTurns { 7.0f };
bool ditheringEnabled { true };
float falloffBias { 0.01f };
float edgeSharpness { 1.0f };
int blurRadius { 4 };
float blurDeviation { 2.5f};
double gpuTime { 0.0 };
};
RenderContext(ItemsConfig items, Tone tone, AmbientOcclusion ao, int drawStatus, bool drawHitEffect, glm::vec4 deferredDebugSize, int deferredDebugMode);
RenderContext() {};
void setArgs(RenderArgs* args) { _args = args; }
RenderArgs* getArgs() { return _args; }
ItemsConfig& getItemsConfig() { return _items; }
Tone& getTone() { return _tone; }
AmbientOcclusion& getAmbientOcclusion() { return _ambientOcclusion; }
int getDrawStatus() { return _drawStatus; }
bool getDrawHitEffect() { return _drawHitEffect; }
bool getOcclusionStatus() { return _occlusionStatus; }
bool getFxaaStatus() { return _fxaaStatus; }
bool getShadowMapStatus() { return _shadowMapStatus; }
void setOptions(bool occlusion, bool fxaa, bool showOwned, bool shadowMap);
// Debugging
int _deferredDebugMode;
glm::vec4 _deferredDebugSize;
protected:
RenderArgs* _args;
// Options
int _drawStatus; // bitflag
bool _drawHitEffect;
bool _occlusionStatus { false };
bool _fxaaStatus { false };
bool _shadowMapStatus { false };
ItemsConfig _items;
Tone _tone;
AmbientOcclusion _ambientOcclusion;
RenderArgs* args;
std::shared_ptr<JobConfig> jobConfig{ nullptr };
};
typedef std::shared_ptr<RenderContext> RenderContextPointer;
using RenderContextPointer = std::shared_ptr<RenderContext>;
}

View file

@ -27,7 +27,10 @@
using namespace render;
void DrawStatusConfig::dirtyHelper() {
enabled = showNetwork || showDisplay;
emit dirty();
}
const gpu::PipelinePointer DrawStatus::getDrawItemBoundsPipeline() {
if (!_drawItemBoundsPipeline) {
@ -94,12 +97,17 @@ const gpu::TexturePointer DrawStatus::getStatusIconMap() const {
return _statusIconMap;
}
void DrawStatus::configure(const Config& config) {
_showDisplay = config.showDisplay;
_showNetwork = config.showNetwork;
}
void DrawStatus::run(const SceneContextPointer& sceneContext,
const RenderContextPointer& renderContext,
const ItemIDsBounds& inItems) {
assert(renderContext->getArgs());
assert(renderContext->getArgs()->_viewFrustum);
RenderArgs* args = renderContext->getArgs();
assert(renderContext->args);
assert(renderContext->args->_viewFrustum);
RenderArgs* args = renderContext->args;
auto& scene = sceneContext->_scene;
const int NUM_STATUS_VEC4_PER_ITEM = 2;
const int VEC4_LENGTH = 4;
@ -179,7 +187,7 @@ void DrawStatus::run(const SceneContextPointer& sceneContext,
const unsigned int VEC3_ADRESS_OFFSET = 3;
if ((renderContext->getDrawStatus() & showDisplayStatusFlag) > 0) {
if (_showDisplay) {
for (int i = 0; i < nbItems; i++) {
batch._glUniform3fv(_drawItemBoundPosLoc, 1, (const float*) (itemAABox + i));
batch._glUniform3fv(_drawItemBoundDimLoc, 1, ((const float*) (itemAABox + i)) + VEC3_ADRESS_OFFSET);
@ -192,7 +200,7 @@ void DrawStatus::run(const SceneContextPointer& sceneContext,
batch.setPipeline(getDrawItemStatusPipeline());
if ((renderContext->getDrawStatus() & showNetworkStatusFlag) > 0) {
if (_showNetwork) {
for (int i = 0; i < nbItems; i++) {
batch._glUniform3fv(_drawItemStatusPosLoc, 1, (const float*) (itemAABox + i));
batch._glUniform3fv(_drawItemStatusDimLoc, 1, ((const float*) (itemAABox + i)) + VEC3_ADRESS_OFFSET);

View file

@ -16,7 +16,47 @@
#include "gpu/Batch.h"
namespace render {
class DrawStatusConfig : public Job::Config {
Q_OBJECT
Q_PROPERTY(bool showDisplay MEMBER showDisplay WRITE setShowDisplay)
Q_PROPERTY(bool showNetwork MEMBER showNetwork WRITE setShowNetwork)
public:
DrawStatusConfig() : Job::Config(false) {}
void dirtyHelper();
bool showDisplay{ false };
bool showNetwork{ false };
public slots:
void setShowDisplay(bool enabled) { showDisplay = enabled; dirtyHelper(); }
void setShowNetwork(bool enabled) { showNetwork = enabled; dirtyHelper(); }
signals:
void dirty();
};
class DrawStatus {
public:
using Config = DrawStatusConfig;
using JobModel = Job::ModelI<DrawStatus, ItemIDsBounds, Config>;
DrawStatus() {}
DrawStatus(const gpu::TexturePointer statusIconMap) { setStatusIconMap(statusIconMap); }
void configure(const Config& config);
void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems);
const gpu::PipelinePointer getDrawItemBoundsPipeline();
const gpu::PipelinePointer getDrawItemStatusPipeline();
void setStatusIconMap(const gpu::TexturePointer& map);
const gpu::TexturePointer getStatusIconMap() const;
protected:
bool _showDisplay; // initialized by Config
bool _showNetwork; // initialized by Config
int _drawItemBoundPosLoc = -1;
int _drawItemBoundDimLoc = -1;
int _drawItemStatusPosLoc = -1;
@ -30,21 +70,6 @@ namespace render {
gpu::BufferPointer _itemBounds;
gpu::BufferPointer _itemStatus;
gpu::TexturePointer _statusIconMap;
public:
DrawStatus() {}
DrawStatus(const gpu::TexturePointer statusIconMap) { setStatusIconMap(statusIconMap); }
void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems);
using JobModel = Task::Job::ModelI<DrawStatus, ItemIDsBounds>;
const gpu::PipelinePointer getDrawItemBoundsPipeline();
const gpu::PipelinePointer getDrawItemStatusPipeline();
void setStatusIconMap(const gpu::TexturePointer& map);
const gpu::TexturePointer getStatusIconMap() const;
};
}

View file

@ -22,10 +22,10 @@ using namespace render;
void render::cullItems(const RenderContextPointer& renderContext, const CullFunctor& cullFunctor, RenderDetails::Item& details,
const ItemIDsBounds& inItems, ItemIDsBounds& outItems) {
assert(renderContext->getArgs());
assert(renderContext->getArgs()->_viewFrustum);
assert(renderContext->args);
assert(renderContext->args->_viewFrustum);
RenderArgs* args = renderContext->getArgs();
RenderArgs* args = renderContext->args;
ViewFrustum* frustum = args->_viewFrustum;
details._considered += inItems.size();
@ -86,11 +86,11 @@ struct BackToFrontSort {
};
void render::depthSortItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, bool frontToBack, const ItemIDsBounds& inItems, ItemIDsBounds& outItems) {
assert(renderContext->getArgs());
assert(renderContext->getArgs()->_viewFrustum);
assert(renderContext->args);
assert(renderContext->args->_viewFrustum);
auto& scene = sceneContext->_scene;
RenderArgs* args = renderContext->getArgs();
RenderArgs* args = renderContext->args;
// Allocate and simply copy
@ -127,7 +127,7 @@ void render::depthSortItems(const SceneContextPointer& sceneContext, const Rende
void render::renderItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems) {
auto& scene = sceneContext->_scene;
RenderArgs* args = renderContext->getArgs();
RenderArgs* args = renderContext->args;
for (const auto& itemDetails : inItems) {
auto& item = scene->getItem(itemDetails.id);
@ -153,7 +153,7 @@ void renderShape(RenderArgs* args, const ShapePlumberPointer& shapeContext, cons
void render::renderShapes(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext,
const ShapePlumberPointer& shapeContext, const ItemIDsBounds& inItems, int maxDrawnItems) {
auto& scene = sceneContext->_scene;
RenderArgs* args = renderContext->getArgs();
RenderArgs* args = renderContext->args;
auto numItemsToDraw = glm::max((int)inItems.size(), maxDrawnItems);
for (auto i = 0; i < numItemsToDraw; ++i) {
@ -177,9 +177,7 @@ void FetchItems::run(const SceneContextPointer& sceneContext, const RenderContex
}
}
if (_probeNumItems) {
_probeNumItems(renderContext, (int)outItems.size());
}
std::static_pointer_cast<Config>(renderContext->jobConfig)->numItems = (int)outItems.size();
}
void DepthSortItems::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outItems) {
@ -187,8 +185,8 @@ void DepthSortItems::run(const SceneContextPointer& sceneContext, const RenderCo
}
void DrawLight::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
assert(renderContext->getArgs());
assert(renderContext->getArgs()->_viewFrustum);
assert(renderContext->args);
assert(renderContext->args->_viewFrustum);
// render lights
auto& scene = sceneContext->_scene;
@ -201,7 +199,7 @@ void DrawLight::run(const SceneContextPointer& sceneContext, const RenderContext
inItems.emplace_back(ItemIDAndBounds(id, item.getBound()));
}
RenderArgs* args = renderContext->getArgs();
RenderArgs* args = renderContext->args;
auto& details = args->_details.edit(RenderDetails::OTHER_ITEM);
ItemIDsBounds culledItems;

View file

@ -27,34 +27,43 @@ void depthSortItems(const SceneContextPointer& sceneContext, const RenderContext
void renderItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems);
void renderShapes(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ShapePlumberPointer& shapeContext, const ItemIDsBounds& inItems, int maxDrawnItems = -1);
class FetchItems {
class FetchItemsConfig : public Job::Config {
Q_OBJECT
Q_PROPERTY(int numItems READ getNumItems)
public:
typedef std::function<void (const RenderContextPointer& context, int count)> ProbeNumItems;
FetchItems() {}
FetchItems(const ProbeNumItems& probe): _probeNumItems(probe) {}
FetchItems(const ItemFilter& filter, const ProbeNumItems& probe): _filter(filter), _probeNumItems(probe) {}
int getNumItems() { return numItems; }
ItemFilter _filter = ItemFilter::Builder::opaqueShape().withoutLayered();
ProbeNumItems _probeNumItems;
void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, ItemIDsBounds& outItems);
using JobModel = Task::Job::ModelO<FetchItems, ItemIDsBounds>;
int numItems{ 0 };
};
template<RenderDetails::Type T = RenderDetails::Type::OTHER_ITEM>
class FetchItems {
public:
using Config = FetchItemsConfig;
using JobModel = Job::ModelO<FetchItems, ItemIDsBounds, Config>;
FetchItems() {}
FetchItems(const ItemFilter& filter) : _filter(filter) {}
ItemFilter _filter{ ItemFilter::Builder::opaqueShape().withoutLayered() };
void configure(const Config& config) {}
void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, ItemIDsBounds& outItems);
};
template<RenderDetails::Type T>
class CullItems {
public:
CullItems(CullFunctor cullFunctor) : _cullFunctor{ cullFunctor } {}
void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outItems) {
const auto& args = renderContext->getArgs();
const auto& args = renderContext->args;
auto& details = args->_details.edit(T);
outItems.clear();
outItems.reserve(inItems.size());
render::cullItems(renderContext, _cullFunctor, details, inItems, outItems);
}
using JobModel = Task::Job::ModelIO<CullItems<T>, ItemIDsBounds, ItemIDsBounds>;
using JobModel = Job::ModelIO<CullItems<T>, ItemIDsBounds, ItemIDsBounds>;
protected:
CullFunctor _cullFunctor;
@ -66,14 +75,14 @@ public:
DepthSortItems(bool frontToBack = true) : _frontToBack(frontToBack) {}
void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outItems);
using JobModel = Task::Job::ModelIO<DepthSortItems, ItemIDsBounds, ItemIDsBounds>;
using JobModel = Job::ModelIO<DepthSortItems, ItemIDsBounds, ItemIDsBounds>;
};
class DrawLight {
public:
DrawLight(CullFunctor cullFunctor) : _cullFunctor{ cullFunctor } {}
void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext);
using JobModel = Task::Job::Model<DrawLight>;
using JobModel = Job::Model<DrawLight>;
protected:
CullFunctor _cullFunctor;
@ -82,7 +91,7 @@ protected:
class PipelineSortShapes {
public:
void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ShapesIDsBounds& outShapes);
using JobModel = Task::Job::ModelIO<PipelineSortShapes, ItemIDsBounds, ShapesIDsBounds>;
using JobModel = Job::ModelIO<PipelineSortShapes, ItemIDsBounds, ShapesIDsBounds>;
};
class DepthSortShapes {
@ -91,7 +100,7 @@ public:
DepthSortShapes(bool frontToBack = true) : _frontToBack(frontToBack) {}
void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ShapesIDsBounds& inShapes, ShapesIDsBounds& outShapes);
using JobModel = Task::Job::ModelIO<DepthSortShapes, ShapesIDsBounds, ShapesIDsBounds>;
using JobModel = Job::ModelIO<DepthSortShapes, ShapesIDsBounds, ShapesIDsBounds>;
};
}

View file

@ -17,29 +17,14 @@ using namespace render;
Engine::Engine() :
_sceneContext(std::make_shared<SceneContext>()),
_renderContext(std::make_shared<RenderContext>())
{
}
void Engine::registerScene(const ScenePointer& scene) {
_sceneContext->_scene = scene;
}
void Engine::setRenderContext(const RenderContext& renderContext) {
(*_renderContext) = renderContext;
}
void Engine::addTask(const TaskPointer& task) {
if (task) {
_tasks.push_back(task);
}
_renderContext(std::make_shared<RenderContext>()) {
}
void Engine::run() {
// Sync GPU state before beginning to render
_renderContext->getArgs()->_context->syncCache();
_renderContext->args->_context->syncCache();
for (auto task : _tasks) {
task->run(_sceneContext, _renderContext);
for (auto job : _jobs) {
job.run(_sceneContext, _renderContext);
}
}

View file

@ -17,36 +17,31 @@
namespace render {
// The root of the tasks, the Engine, should not be known from the Tasks,
// The SceneContext is what navigates from the engine down to the Tasks
class Engine {
// The render engine holds all render tasks, and is itself a render task.
// State flows through tasks to jobs via the render and scene contexts -
// the engine should not be known from its jobs.
class Engine : public Task {
public:
Engine();
~Engine() {}
~Engine() = default;
// Register the scene should be [art of the init phase before running the engine
void registerScene(const ScenePointer& scene);
// Register the scene
void registerScene(const ScenePointer& scene) { _sceneContext->_scene = scene; }
// Push a RenderContext
void setRenderContext(const RenderContext& renderContext);
void setRenderContext(const RenderContext& renderContext) { (*_renderContext) = renderContext; }
RenderContextPointer getRenderContext() const { return _renderContext; }
void addTask(const TaskPointer& task);
const Tasks& getTasks() const { return _tasks; }
// Render a frame
// A frame must have a scene registered and a context set to render
void run();
protected:
Tasks _tasks;
SceneContextPointer _sceneContext;
RenderContextPointer _renderContext;
};
typedef std::shared_ptr<Engine> EnginePointer;
using EnginePointer = std::shared_ptr<Engine>;
}
#endif // hifi_render_Engine_h

View file

@ -0,0 +1,25 @@
//
// Task.cpp
// render/src/render
//
// Created by Zach Pomerantz on 1/21/2016.
// Copyright 2016 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 <QtCore/QThread>
#include "Task.h"
using namespace render;
void TaskConfig::refresh() {
if (QThread::currentThread() != thread()) {
QMetaObject::invokeMethod(this, "refresh", Qt::BlockingQueuedConnection);
return;
}
_task->configure(*this);
}

View file

@ -2,8 +2,8 @@
// Task.h
// render/src/render
//
// Created by Zach Pomerantz on 1/6/2015.
// Copyright 2015 High Fidelity, Inc.
// Created by Zach Pomerantz on 1/6/2016.
// Copyright 2016 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
@ -12,6 +12,8 @@
#ifndef hifi_render_Task_h
#define hifi_render_Task_h
#include <qscriptengine.h> // QObject
#include "Context.h"
#include "gpu/Batch.h"
@ -48,180 +50,296 @@ protected:
std::shared_ptr<Concept> _concept;
};
// FIXME: In c++17, use default classes of nullptr_t to combine these
template <class T> void jobRun(T& jobModel, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
jobModel.run(sceneContext, renderContext);
}
template <class T, class I> void jobRunI(T& jobModel, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const I& input) {
jobModel.run(sceneContext, renderContext, input);
}
template <class T, class O> void jobRunO(T& jobModel, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, O& output) {
jobModel.run(sceneContext, renderContext, output);
}
template <class T, class I, class O> void jobRunIO(T& jobModel, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const I& input, O& output) {
jobModel.run(sceneContext, renderContext, input, output);
}
class Job;
class Task;
// The base class for a task that runs on the SceneContext
class Task {
// A default Config is always on; to create an enableable Config, use the ctor JobConfig(bool enabled)
class JobConfig : public QObject {
Q_OBJECT
public:
// The guts of a task; tasks are composed of multiple Jobs that execute serially
class Job {
JobConfig() = default;
JobConfig(bool enabled) : alwaysEnabled{ false }, enabled{ enabled } {}
bool isEnabled() { return alwaysEnabled || enabled; }
bool alwaysEnabled{ true };
bool enabled{ true };
};
class TaskConfig : public JobConfig {
Q_OBJECT
public:
TaskConfig() = default ;
TaskConfig(bool enabled) : JobConfig(enabled) {}
void init(Task* task) { _task = task; }
template <class T> typename T::Config* getConfig(std::string job = "") const {
QString name = job.empty() ? QString() : QString(job.c_str()); // an empty string is not a null string
return findChild<typename T::Config*>(name);
}
template <class T> void setJobEnabled(bool enable = true, std::string job = "") {
assert(getConfig<T>(job)->alwaysEnabled != true);
getConfig<T>(job)->enabled = enable;
refresh(); // trigger a Job->configure
}
template <class T> bool isJobEnabled(bool enable = true, std::string job = "") const {
return getConfig<T>(job)->isEnabled();
}
public slots:
void refresh();
private:
Task* _task;
};
template <class T, class C> void jobConfigure(T& data, const C& configuration) {
data.configure(configuration);
}
template<class T> void jobConfigure(T&, const JobConfig&) {
// nop, as the default JobConfig was used, so the data does not need a configure method
}
template <class T> void jobRun(T& data, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
data.run(sceneContext, renderContext);
}
template <class T, class I> void jobRunI(T& data, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const I& input) {
data.run(sceneContext, renderContext, input);
}
template <class T, class O> void jobRunO(T& data, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, O& output) {
data.run(sceneContext, renderContext, output);
}
template <class T, class I, class O> void jobRunIO(T& data, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const I& input, O& output) {
data.run(sceneContext, renderContext, input, output);
}
class Job {
public:
using Config = JobConfig;
using QConfigPointer = std::shared_ptr<QObject>;
// The guts of a job
class Concept {
public:
friend class Task;
Concept(QConfigPointer config) : _config(config) {}
virtual ~Concept() = default;
// The guts of a job; jobs are composed of a concept
class Concept {
public:
Concept() = default;
virtual ~Concept() = default;
virtual const Varying getInput() const { return Varying(); }
virtual const Varying getOutput() const { return Varying(); }
bool isEnabled() const { return _isEnabled; }
void setEnabled(bool isEnabled) { _isEnabled = isEnabled; }
virtual QConfigPointer& getConfiguration() { return _config; }
virtual void applyConfiguration() = 0;
virtual const Varying getInput() const { return Varying(); }
virtual const Varying getOutput() const { return Varying(); }
virtual void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) = 0;
virtual void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) = 0;
protected:
protected:
QConfigPointer _config;
};
using ConceptPointer = std::shared_ptr<Concept>;
bool _isEnabled = true;
};
using ConceptPointer = std::shared_ptr<Concept>;
template <class T, class C = Config> class Model : public Concept {
public:
using Data = T;
Data _data;
template <class T> class Model : public Concept {
public:
typedef T Data;
Data _data;
Model() {}
Model(Data data): _data(data) {}
void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
if (isEnabled()) {
jobRun(_data, sceneContext, renderContext);
}
}
};
template <class T, class I> class ModelI : public Concept {
public:
typedef T Data;
typedef I Input;
Data _data;
Varying _input;
const Varying getInput() const { return _input; }
ModelI(const Varying& input, Data data = Data()) : _data(data), _input(input) {}
ModelI(Data data) : _data(data) {}
void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
if (isEnabled()) {
jobRunI(_data, sceneContext, renderContext, _input.get<I>());
}
}
};
template <class T, class O> class ModelO : public Concept {
public:
typedef T Data;
typedef O Output;
Data _data;
Varying _output;
const Varying getOutput() const { return _output; }
ModelO(Data data) : _data(data), _output(Output()) {}
ModelO() : _output(Output()) {}
void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
if (isEnabled()) {
jobRunO(_data, sceneContext, renderContext, _output.edit<O>());
}
}
};
template <class T, class I, class O> class ModelIO : public Concept {
public:
typedef T Data;
typedef I Input;
typedef O Output;
Data _data;
Varying _input;
Varying _output;
const Varying getInput() const { return _input; }
const Varying getOutput() const { return _output; }
ModelIO(const Varying& input, Data data = Data()) : _data(data), _input(input), _output(Output()) {}
ModelIO(Data data) : _data(data), _output(Output()) {}
void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
if (isEnabled()) {
jobRunIO(_data, sceneContext, renderContext, _input.get<I>(), _output.edit<O>());
}
}
};
Job(ConceptPointer concept) : _concept(concept) {}
Job(std::string name, ConceptPointer concept) : _concept(concept), _name(name) {}
bool isEnabled() const { return _concept->isEnabled(); }
void setEnabled(bool isEnabled) { _concept->setEnabled(isEnabled); }
const Varying getInput() const { return _concept->getInput(); }
const Varying getOutput() const { return _concept->getOutput(); }
template <class T> T& edit() {
auto concept = std::static_pointer_cast<typename T::JobModel>(_concept);
assert(concept);
return concept->_data;
Model(Data data = Data()) : Concept(std::make_shared<C>()), _data(data) {
applyConfiguration();
}
template <class T> const T& get() const {
auto concept = std::static_pointer_cast<typename T::JobModel>(_concept);
assert(concept);
return concept->_data;
void applyConfiguration() {
jobConfigure(_data, *std::static_pointer_cast<C>(_config));
}
void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
PerformanceTimer perfTimer(_name.c_str());
PROFILE_RANGE(_name.c_str());
_concept->run(sceneContext, renderContext);
renderContext->jobConfig = std::static_pointer_cast<Config>(_config);
if (renderContext->jobConfig->alwaysEnabled || renderContext->jobConfig->enabled) {
jobRun(_data, sceneContext, renderContext);
}
renderContext->jobConfig.reset();
}
protected:
ConceptPointer _concept;
std::string _name = "";
};
template <class T, class I, class C = Config> class ModelI : public Concept {
public:
using Data = T;
using Input = I;
Data _data;
Varying _input;
const Varying getInput() const { return _input; }
ModelI(const Varying& input, Data data = Data()) : Concept(std::make_shared<C>()), _data(data), _input(input) {
applyConfiguration();
}
void applyConfiguration() {
jobConfigure(_data, *std::static_pointer_cast<C>(_config));
}
void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
renderContext->jobConfig = std::static_pointer_cast<Config>(_config);
if (renderContext->jobConfig->alwaysEnabled || renderContext->jobConfig->enabled) {
jobRunI(_data, sceneContext, renderContext, _input.get<I>());
}
renderContext->jobConfig.reset();
}
};
template <class T, class O, class C = Config> class ModelO : public Concept {
public:
using Data = T;
using Output = O;
Data _data;
Varying _output;
const Varying getOutput() const { return _output; }
ModelO(Data data = Data()) : Concept(std::make_shared<C>()), _data(data), _output(Output()) {
applyConfiguration();
}
void applyConfiguration() {
jobConfigure(_data, *std::static_pointer_cast<C>(_config));
}
void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
renderContext->jobConfig = std::static_pointer_cast<Config>(_config);
if (renderContext->jobConfig->alwaysEnabled || renderContext->jobConfig->enabled) {
jobRunO(_data, sceneContext, renderContext, _output.edit<O>());
}
renderContext->jobConfig.reset();
}
};
template <class T, class I, class O, class C = Config> class ModelIO : public Concept {
public:
using Data = T;
using Input = I;
using Output = O;
Data _data;
Varying _input;
Varying _output;
const Varying getInput() const { return _input; }
const Varying getOutput() const { return _output; }
ModelIO(const Varying& input, Data data = Data()) : Concept(std::make_shared<C>()), _data(data), _input(input), _output(Output()) {
applyConfiguration();
}
void applyConfiguration() {
jobConfigure(_data, *std::static_pointer_cast<C>(_config));
}
void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
renderContext->jobConfig = std::static_pointer_cast<Config>(_config);
if (renderContext->jobConfig->alwaysEnabled || renderContext->jobConfig->enabled) {
jobRunIO(_data, sceneContext, renderContext, _input.get<I>(), _output.edit<O>());
}
renderContext->jobConfig.reset();
}
};
Job(std::string name, ConceptPointer concept) : _concept(concept), _name(name) {}
const Varying getInput() const { return _concept->getInput(); }
const Varying getOutput() const { return _concept->getOutput(); }
QConfigPointer& getConfiguration() const { return _concept->getConfiguration(); }
void applyConfiguration() { return _concept->applyConfiguration(); }
template <class T> T& edit() {
auto concept = std::static_pointer_cast<typename T::JobModel>(_concept);
assert(concept);
return concept->_data;
}
void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
PerformanceTimer perfTimer(_name.c_str());
PROFILE_RANGE(_name.c_str());
_concept->run(sceneContext, renderContext);
}
protected:
ConceptPointer _concept;
std::string _name = "";
};
// A task is a specialized job to run a collection of other jobs
// It is defined with JobModel = Task::Model<T>
//
// A task with a custom config *must* use the templated constructor
class Task {
public:
using Config = TaskConfig;
using QConfigPointer = Job::QConfigPointer;
template <class T, class C = Config> class Model : public Job::Concept {
public:
using Data = T;
Data _data;
Model(Data data = Data()) : Concept(std::make_shared<C>()), _data(data) {
_config = _data._config; // use the data's config
std::static_pointer_cast<Config>(_config)->init(&_data);
applyConfiguration();
}
void applyConfiguration() {
jobConfigure(_data, *std::static_pointer_cast<C>(_config));
}
void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
renderContext->jobConfig = std::static_pointer_cast<Config>(_config);
if (renderContext->jobConfig->alwaysEnabled || renderContext->jobConfig->enabled) {
jobRun(_data, sceneContext, renderContext);
}
renderContext->jobConfig.reset();
}
};
using Jobs = std::vector<Job>;
public:
Task() = default;
virtual ~Task() = default;
// A task must use its Config for construction
Task() : _config{ std::make_shared<Config>() } {}
template <class C> Task(std::shared_ptr<C> config) : _config{ config } {}
// Queue a new job to the task; returns the job's index
// Queue a new job to the container; returns the job's output
template <class T, class... A> const Varying addJob(std::string name, A&&... args) {
_jobs.emplace_back(name, std::make_shared<typename T::JobModel>(std::forward<A>(args)...));
QConfigPointer config = _jobs.back().getConfiguration();
config->setParent(_config.get());
config->setObjectName(name.c_str());
QObject::connect(config.get(), SIGNAL(dirty()), _config.get(), SLOT(refresh()));
return _jobs.back().getOutput();
}
void enableJob(size_t jobIndex, bool enable = true) { _jobs.at(jobIndex).setEnabled(enable); }
bool getEnableJob(size_t jobIndex) const { return _jobs.at(jobIndex).isEnabled(); }
std::shared_ptr<Config> getConfiguration() {
auto config = std::static_pointer_cast<Config>(_config);
// If we are here, we were not made by a Model, so we must initialize our own config
config->init(this);
return config;
}
virtual void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {}
void configure(const QObject& configuration) {
for (auto& job : _jobs) {
job.applyConfiguration();
}
}
protected:
template <class T, class C> friend class Model;
QConfigPointer _config;
Jobs _jobs;
};
typedef std::shared_ptr<Task> TaskPointer;
typedef std::vector<TaskPointer> Tasks;
}