diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 6a50bf8368..c601150e2e 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -98,6 +98,7 @@ #include #include #include +#include #include #include #include @@ -1745,10 +1746,14 @@ void Application::initializeGL() { // Set up the render engine render::CullFunctor cullFunctor = LODManager::shouldRender; _renderEngine->addJob("RenderShadowTask", cullFunctor); - _renderEngine->addJob("RenderDeferredTask", cullFunctor); + static const QString RENDER_FORWARD = "RENDER_FORWARD"; + if (QProcessEnvironment::systemEnvironment().contains(RENDER_FORWARD)) { + _renderEngine->addJob("RenderForwardTask", cullFunctor); + } else { + _renderEngine->addJob("RenderDeferredTask", cullFunctor); + } _renderEngine->load(); _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 diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp index 2c6440094b..a4cb62cc13 100644 --- a/interface/src/ui/PreferencesDialog.cpp +++ b/interface/src/ui/PreferencesDialog.cpp @@ -292,23 +292,24 @@ void setupPreferences() { { static const QString RENDER("Graphics"); auto renderConfig = qApp->getRenderEngine()->getConfiguration(); + if (renderConfig) { + auto ambientOcclusionConfig = renderConfig->getConfig(); + if (ambientOcclusionConfig) { + auto getter = [ambientOcclusionConfig]()->QString { return ambientOcclusionConfig->getPreset(); }; + auto setter = [ambientOcclusionConfig](QString preset) { ambientOcclusionConfig->setPreset(preset); }; + auto preference = new ComboBoxPreference(RENDER, "Ambient occlusion", getter, setter); + preference->setItems(ambientOcclusionConfig->getPresetList()); + preferences->addPreference(preference); + } - auto ambientOcclusionConfig = renderConfig->getConfig(); - { - auto getter = [ambientOcclusionConfig]()->QString { return ambientOcclusionConfig->getPreset(); }; - auto setter = [ambientOcclusionConfig](QString preset) { ambientOcclusionConfig->setPreset(preset); }; - auto preference = new ComboBoxPreference(RENDER, "Ambient occlusion", getter, setter); - preference->setItems(ambientOcclusionConfig->getPresetList()); - preferences->addPreference(preference); - } - - auto shadowConfig = renderConfig->getConfig(); - { - auto getter = [shadowConfig]()->QString { return shadowConfig->getPreset(); }; - auto setter = [shadowConfig](QString preset) { shadowConfig->setPreset(preset); }; - auto preference = new ComboBoxPreference(RENDER, "Shadows", getter, setter); - preference->setItems(shadowConfig->getPresetList()); - preferences->addPreference(preference); + auto shadowConfig = renderConfig->getConfig(); + if (shadowConfig) { + auto getter = [shadowConfig]()->QString { return shadowConfig->getPreset(); }; + auto setter = [shadowConfig](QString preset) { shadowConfig->setPreset(preset); }; + auto preference = new ComboBoxPreference(RENDER, "Shadows", getter, setter); + preference->setItems(shadowConfig->getPresetList()); + preferences->addPreference(preference); + } } } { diff --git a/libraries/render-utils/src/RenderForwardTask.cpp b/libraries/render-utils/src/RenderForwardTask.cpp new file mode 100755 index 0000000000..da7fcf5cdd --- /dev/null +++ b/libraries/render-utils/src/RenderForwardTask.cpp @@ -0,0 +1,163 @@ + +// +// RenderForwardTask.cpp +// render-utils/src/ +// +// Created by Zach Pomerantz on 12/13/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 "RenderForwardTask.h" +#include "RenderDeferredTask.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "LightingModel.h" +#include "DebugDeferredBuffer.h" +#include "DeferredFramebuffer.h" +#include "DeferredLightingEffect.h" +#include "SurfaceGeometryPass.h" +#include "FramebufferCache.h" +#include "HitEffect.h" +#include "TextureCache.h" + +#include "AmbientOcclusionEffect.h" +#include "AntialiasingEffect.h" +#include "ToneMappingEffect.h" +#include "SubsurfaceScattering.h" + +#include + +#include "drawOpaqueStencil_frag.h" + + +using namespace render; +extern void initOverlay3DPipelines(render::ShapePlumber& plumber); +extern void initDeferredPipelines(render::ShapePlumber& plumber); + +RenderForwardTask::RenderForwardTask(CullFunctor cullFunctor) { + // Prepare the ShapePipelines + ShapePlumberPointer shapePlumber = std::make_shared(); + initDeferredPipelines(*shapePlumber); + + // CPU jobs: + // Fetch and cull the items from the scene + const auto spatialSelection = addJob("FetchSceneSelection"); + + cullFunctor = cullFunctor ? cullFunctor : [](const RenderArgs*, const AABox&){ return true; }; + auto spatialFilter = ItemFilter::Builder::visibleWorldItems().withoutLayered(); + const auto culledSpatialSelection = addJob("CullSceneSelection", spatialSelection, cullFunctor, RenderDetails::ITEM, spatialFilter); + + // Overlays are not culled + const auto nonspatialSelection = addJob("FetchOverlaySelection"); + + // Multi filter visible items into different buckets + const int NUM_FILTERS = 3; + const int OPAQUE_SHAPE_BUCKET = 0; + const int TRANSPARENT_SHAPE_BUCKET = 1; + const int LIGHT_BUCKET = 2; + const int BACKGROUND_BUCKET = 2; + MultiFilterItem::ItemFilterArray spatialFilters = { { + ItemFilter::Builder::opaqueShape(), + ItemFilter::Builder::transparentShape(), + ItemFilter::Builder::light() + } }; + MultiFilterItem::ItemFilterArray nonspatialFilters = { { + ItemFilter::Builder::opaqueShape(), + ItemFilter::Builder::transparentShape(), + ItemFilter::Builder::background() + } }; + const auto filteredSpatialBuckets = addJob>("FilterSceneSelection", culledSpatialSelection, spatialFilters).get::ItemBoundsArray>(); + const auto filteredNonspatialBuckets = addJob>("FilterOverlaySelection", nonspatialSelection, nonspatialFilters).get::ItemBoundsArray>(); + + // Extract / Sort opaques / Transparents / Lights / Overlays + const auto opaques = addJob("DepthSortOpaque", filteredSpatialBuckets[OPAQUE_SHAPE_BUCKET]); + const auto transparents = addJob("DepthSortTransparent", filteredSpatialBuckets[TRANSPARENT_SHAPE_BUCKET], DepthSortItems(false)); + const auto lights = filteredSpatialBuckets[LIGHT_BUCKET]; + + const auto overlayOpaques = addJob("DepthSortOverlayOpaque", filteredNonspatialBuckets[OPAQUE_SHAPE_BUCKET]); + const auto overlayTransparents = addJob("DepthSortOverlayTransparent", filteredNonspatialBuckets[TRANSPARENT_SHAPE_BUCKET], DepthSortItems(false)); + const auto background = filteredNonspatialBuckets[BACKGROUND_BUCKET]; + + const auto framebuffer = addJob("PrepareFramebuffer"); + + // Blit! + addJob("Blit", framebuffer); +} + +void RenderForwardTask::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { + // sanity checks + assert(sceneContext); + if (!sceneContext->_scene) { + return; + } + + + // Is it possible that we render without a viewFrustum ? + if (!(renderContext->args && renderContext->args->hasViewFrustum())) { + return; + } + + auto config = std::static_pointer_cast(renderContext->jobConfig); + + for (auto job : _jobs) { + job.run(sceneContext, renderContext); + } +} + +void PrepareFramebuffer::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, gpu::FramebufferPointer& framebuffer) { + auto framebufferCache = DependencyManager::get(); + auto framebufferSize = framebufferCache->getFrameBufferSize(); + glm::uvec2 frameSize(framebufferSize.width(), framebufferSize.height()); + + // Resizing framebuffers instead of re-building them seems to cause issues with threaded rendering + if (_framebuffer && _framebuffer->getSize() != frameSize) { + _framebuffer.reset(); + } + + if (!_framebuffer) { + _framebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("forward")); + + auto colorFormat = gpu::Element::COLOR_SRGBA_32; + auto defaultSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_POINT); + auto colorTexture = gpu::TexturePointer(gpu::Texture::create2D(colorFormat, frameSize.x, frameSize.y, defaultSampler)); + _framebuffer->setRenderBuffer(0, colorTexture); + + auto depthFormat = gpu::Element(gpu::SCALAR, gpu::UINT32, gpu::DEPTH_STENCIL); // Depth24_Stencil8 texel format + auto depthTexture = gpu::TexturePointer(gpu::Texture::create2D(depthFormat, frameSize.x, frameSize.y, defaultSampler)); + _framebuffer->setDepthStencilBuffer(depthTexture, depthFormat); + } + + auto args = renderContext->args; + gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { + batch.enableStereo(false); + batch.setViewportTransform(args->_viewport); + batch.setStateScissorRect(args->_viewport); + + batch.setFramebuffer(_framebuffer); + batch.clearFramebuffer( + gpu::Framebuffer::BUFFER_COLOR0 | + gpu::Framebuffer::BUFFER_COLOR1 | + gpu::Framebuffer::BUFFER_COLOR2 | + gpu::Framebuffer::BUFFER_COLOR3 | + gpu::Framebuffer::BUFFER_DEPTH | + gpu::Framebuffer::BUFFER_STENCIL, + vec4(vec3(0), 0), 1.0, 0.0, true); + }); + + framebuffer = _framebuffer; +} diff --git a/libraries/render-utils/src/RenderForwardTask.h b/libraries/render-utils/src/RenderForwardTask.h new file mode 100755 index 0000000000..9c4634a8ee --- /dev/null +++ b/libraries/render-utils/src/RenderForwardTask.h @@ -0,0 +1,42 @@ +// +// RenderForwardTask.h +// render-utils/src/ +// +// Created by Zach Pomerantz on 12/13/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 +// + +#ifndef hifi_RenderForwardTask_h +#define hifi_RenderForwardTask_h + +#include +#include +#include "LightingModel.h" + +using RenderForwardTaskConfig = render::GPUTaskConfig; + +class RenderForwardTask : public render::Task { +public: + using Config = RenderForwardTaskConfig; + RenderForwardTask(render::CullFunctor cullFunctor); + + void configure(const Config& config) {} + void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext); + + using JobModel = Model; +}; + +class PrepareFramebuffer { +public: + using JobModel = render::Job::ModelO; + + void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, gpu::FramebufferPointer& framebuffer); + +private: + gpu::FramebufferPointer _framebuffer; +}; + +#endif // hifi_RenderForwardTask_h