mirror of
https://github.com/JulianGro/overte.git
synced 2025-04-15 11:38:16 +02:00
Merge pull request #6930 from zzmp/feat/bubble-render-settings
Bubble up render settings from CPP to JS/QML
This commit is contained in:
commit
f4e0352f61
31 changed files with 838 additions and 989 deletions
|
@ -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
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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*) ¶meters));
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
|
@ -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>;
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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>;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
25
libraries/render/src/render/Task.cpp
Normal file
25
libraries/render/src/render/Task.cpp
Normal 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);
|
||||
}
|
|
@ -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;
|
||||
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue