diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index b056a8e378..dd9c097319 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1828,7 +1828,7 @@ void Application::initializeGL() { assert(items.canCast()); static const QString RENDER_FORWARD = "HIFI_RENDER_FORWARD"; if (QProcessEnvironment::systemEnvironment().contains(RENDER_FORWARD)) { - _renderEngine->addJob("RenderForwardTask", items.get()); + _renderEngine->addJob("Forward", items.get()); } else { _renderEngine->addJob("RenderDeferredTask", items.get()); } diff --git a/libraries/render-utils/src/RenderForwardTask.cpp b/libraries/render-utils/src/RenderForwardTask.cpp index e78d457666..c7a3433c96 100755 --- a/libraries/render-utils/src/RenderForwardTask.cpp +++ b/libraries/render-utils/src/RenderForwardTask.cpp @@ -26,10 +26,16 @@ #include #include +#include "nop_frag.h" using namespace render; +extern void initForwardPipelines(ShapePlumber& plumber); RenderForwardTask::RenderForwardTask(RenderFetchCullSortTask::Output items) { + // Prepare the ShapePipelines + ShapePlumberPointer shapePlumber = std::make_shared(); + initForwardPipelines(*shapePlumber); + // Extract opaques / transparents / lights / overlays const auto opaques = items[0]; const auto transparents = items[1]; @@ -40,16 +46,19 @@ RenderForwardTask::RenderForwardTask(RenderFetchCullSortTask::Output items) { const auto framebuffer = addJob("PrepareFramebuffer"); + addJob("DrawOpaques", opaques, shapePlumber); + addJob("Stencil"); addJob("DrawBackground", background); - // bounds do not draw on stencil buffer, so they must come last + // Bounds do not draw on stencil buffer, so they must come last addJob("DrawBounds", opaques); // Blit! addJob("Blit", framebuffer); } -void PrepareFramebuffer::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, gpu::FramebufferPointer& framebuffer) { +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()); @@ -89,6 +98,88 @@ void PrepareFramebuffer::run(const SceneContextPointer& sceneContext, const Rend framebuffer = _framebuffer; } +void Draw::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, + const Inputs& items) { + RenderArgs* args = renderContext->args; + + gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { + args->_batch = &batch; + + // Setup projection + glm::mat4 projMat; + Transform viewMat; + args->getViewFrustum().evalProjectionMatrix(projMat); + args->getViewFrustum().evalViewTransform(viewMat); + batch.setProjectionTransform(projMat); + batch.setViewTransform(viewMat); + batch.setModelTransform(Transform()); + + // Render items + renderStateSortShapes(sceneContext, renderContext, _shapePlumber, items, -1); + }); + args->_batch = nullptr; +} + +const gpu::PipelinePointer Stencil::getPipeline() { + if (!_stencilPipeline) { + auto vs = gpu::StandardShaderLib::getDrawUnitQuadTexcoordVS(); + auto ps = gpu::Shader::createPixel(std::string(nop_frag)); + gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); + gpu::Shader::makeProgram(*program); + + auto state = std::make_shared(); + state->setDepthTest(true, false, gpu::LESS_EQUAL); + const gpu::int8 STENCIL_OPAQUE = 1; + state->setStencilTest(true, 0xFF, gpu::State::StencilTest(STENCIL_OPAQUE, 0xFF, gpu::ALWAYS, + gpu::State::STENCIL_OP_REPLACE, + gpu::State::STENCIL_OP_REPLACE, + gpu::State::STENCIL_OP_KEEP)); + + _stencilPipeline = gpu::Pipeline::create(program, state); + } + return _stencilPipeline; +} + +void Stencil::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { + RenderArgs* args = renderContext->args; + + gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { + args->_batch = &batch; + + batch.enableStereo(false); + batch.setViewportTransform(args->_viewport); + batch.setStateScissorRect(args->_viewport); + + batch.setPipeline(getPipeline()); + batch.draw(gpu::TRIANGLE_STRIP, 4); + }); + args->_batch = nullptr; +} + +void DrawBackground::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, + const Inputs& background) { + RenderArgs* args = renderContext->args; + + gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { + args->_batch = &batch; + + batch.enableSkybox(true); + batch.setViewportTransform(args->_viewport); + batch.setStateScissorRect(args->_viewport); + + // Setup projection + glm::mat4 projMat; + Transform viewMat; + args->getViewFrustum().evalProjectionMatrix(projMat); + args->getViewFrustum().evalViewTransform(viewMat); + batch.setProjectionTransform(projMat); + batch.setViewTransform(viewMat); + + renderItems(sceneContext, renderContext, background); + }); + args->_batch = nullptr; +} + const gpu::PipelinePointer DrawBounds::getPipeline() { if (!_boundsPipeline) { auto vs = gpu::Shader::createVertex(std::string(drawItemBounds_vert)); @@ -112,7 +203,8 @@ const gpu::PipelinePointer DrawBounds::getPipeline() { return _boundsPipeline; } -void DrawBounds::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const Inputs& items) { +void DrawBounds::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, + const Inputs& items) { RenderArgs* args = renderContext->args; gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { @@ -142,26 +234,3 @@ void DrawBounds::run(const SceneContextPointer& sceneContext, const RenderContex } }); } - -void DrawBackground::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const Inputs& items) { - RenderArgs* args = renderContext->args; - - gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { - args->_batch = &batch; - - batch.enableSkybox(true); - batch.setViewportTransform(args->_viewport); - batch.setStateScissorRect(args->_viewport); - - // Setup projection - glm::mat4 projMat; - Transform viewMat; - args->getViewFrustum().evalProjectionMatrix(projMat); - args->getViewFrustum().evalViewTransform(viewMat); - batch.setProjectionTransform(projMat); - batch.setViewTransform(viewMat); - - renderItems(sceneContext, renderContext, items); - }); - args->_batch = nullptr; -} diff --git a/libraries/render-utils/src/RenderForwardTask.h b/libraries/render-utils/src/RenderForwardTask.h index 000210c761..a957f7493e 100755 --- a/libraries/render-utils/src/RenderForwardTask.h +++ b/libraries/render-utils/src/RenderForwardTask.h @@ -25,20 +25,62 @@ public: class PrepareFramebuffer { public: - using JobModel = render::Job::ModelO; + using Inputs = gpu::FramebufferPointer; + using JobModel = render::Job::ModelO; - void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, gpu::FramebufferPointer& framebuffer); + void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, + gpu::FramebufferPointer& framebuffer); private: gpu::FramebufferPointer _framebuffer; }; -class DrawBounds { +class Draw { public: using Inputs = render::ItemBounds; - using JobModel = render::Job::ModelI; + using JobModel = render::Job::ModelI; - void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, const Inputs& items); + Draw(const render::ShapePlumberPointer& shapePlumber) : _shapePlumber(shapePlumber) {} + void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, + const Inputs& items); + +private: + render::ShapePlumberPointer _shapePlumber; +}; + +class Stencil { +public: + using JobModel = render::Job::Model; + + void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext); + +private: + const gpu::PipelinePointer getPipeline(); + gpu::PipelinePointer _stencilPipeline; +}; + +class DrawBackground { +public: + using Inputs = render::ItemBounds; + using JobModel = render::Job::ModelI; + + void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, + const Inputs& background); +}; + +class DrawBounds { +public: + class Config : public render::JobConfig { + public: + Config() : JobConfig(false) {} + }; + + using Inputs = render::ItemBounds; + using JobModel = render::Job::ModelI; + + void configure(const Config& configuration) {} + void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, + const Inputs& items); private: const gpu::PipelinePointer getPipeline(); @@ -47,12 +89,4 @@ private: int _scaleLocation { -1 }; }; -class DrawBackground { -public: - using Inputs = render::ItemBounds; - using JobModel = render::Job::ModelI; - - void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, const Inputs& background); -}; - #endif // hifi_RenderForwardTask_h diff --git a/libraries/render-utils/src/RenderPipelines.cpp b/libraries/render-utils/src/RenderPipelines.cpp index 1f4b7ca445..b0d676ef78 100644 --- a/libraries/render-utils/src/RenderPipelines.cpp +++ b/libraries/render-utils/src/RenderPipelines.cpp @@ -10,6 +10,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include + #include #include @@ -47,41 +49,17 @@ using namespace render; +using namespace std::placeholders; -gpu::BufferView getDefaultMaterialBuffer() { - model::Material::Schema schema; - schema._albedo = vec3(1.0f); - schema._opacity = 1.0f; - schema._metallic = 0.1f; - schema._roughness = 0.9f; - return gpu::BufferView(std::make_shared(sizeof(model::Material::Schema), (const gpu::Byte*) &schema)); -} +void initOverlay3DPipelines(ShapePlumber& plumber); +void initDeferredPipelines(ShapePlumber& plumber); +void initForwardPipelines(ShapePlumber& plumber); -void batchSetter(const ShapePipeline& pipeline, gpu::Batch& batch) { - // Set a default albedo map - batch.setResourceTexture(render::ShapePipeline::Slot::MAP::ALBEDO, - DependencyManager::get()->getWhiteTexture()); - // Set a default normal map - batch.setResourceTexture(render::ShapePipeline::Slot::MAP::NORMAL_FITTING, - DependencyManager::get()->getNormalFittingTexture()); +void addPlumberPipeline(ShapePlumber& plumber, + const ShapeKey& key, const gpu::ShaderPointer& vertex, const gpu::ShaderPointer& pixel); - // Set a default material - if (pipeline.locations->materialBufferUnit >= 0) { - static const gpu::BufferView OPAQUE_SCHEMA_BUFFER = getDefaultMaterialBuffer(); - batch.setUniformBuffer(ShapePipeline::Slot::BUFFER::MATERIAL, OPAQUE_SCHEMA_BUFFER); - } -} - -void lightBatchSetter(const ShapePipeline& pipeline, gpu::Batch& batch) { - batchSetter(pipeline, batch); - // Set the light - if (pipeline.locations->lightBufferUnit >= 0) { - DependencyManager::get()->setupKeyLightBatch(batch, - pipeline.locations->lightBufferUnit, - pipeline.locations->lightAmbientBufferUnit, - pipeline.locations->lightAmbientMapUnit); - } -} +void batchSetter(const ShapePipeline& pipeline, gpu::Batch& batch); +void lightBatchSetter(const ShapePipeline& pipeline, gpu::Batch& batch); void initOverlay3DPipelines(ShapePlumber& plumber) { auto vertex = gpu::Shader::createVertex(std::string(overlay3D_vert)); @@ -130,50 +108,6 @@ void initOverlay3DPipelines(ShapePlumber& plumber) { } void initDeferredPipelines(render::ShapePlumber& plumber) { - using Key = render::ShapeKey; - using ShaderPointer = gpu::ShaderPointer; - - auto addPipeline = [&plumber](const Key& key, const ShaderPointer& vertexShader, const ShaderPointer& pixelShader) { - // These keyvalues' pipelines will be added by this lamdba in addition to the key passed - assert(!key.isWireFrame()); - assert(!key.isDepthBiased()); - assert(key.isCullFace()); - - ShaderPointer program = gpu::Shader::createProgram(vertexShader, pixelShader); - - for (int i = 0; i < 8; i++) { - bool isCulled = (i & 1); - bool isBiased = (i & 2); - bool isWireframed = (i & 4); - - ShapeKey::Builder builder(key); - auto state = std::make_shared(); - - // Depth test depends on transparency - state->setDepthTest(true, !key.isTranslucent(), gpu::LESS_EQUAL); - state->setBlendFunction(key.isTranslucent(), - gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, - gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); - - if (!isCulled) { - builder.withoutCullFace(); - } - state->setCullMode(isCulled ? gpu::State::CULL_BACK : gpu::State::CULL_NONE); - if (isWireframed) { - builder.withWireframe(); - state->setFillMode(gpu::State::FILL_LINE); - } - if (isBiased) { - builder.withDepthBias(); - state->setDepthBias(1.0f); - state->setDepthBiasSlopeScale(1.0f); - } - - plumber.addPipeline(builder.build(), program, state, - key.isTranslucent() ? &lightBatchSetter : &batchSetter); - } - }; - // Vertex shaders auto modelVertex = gpu::Shader::createVertex(std::string(model_vert)); auto modelNormalMapVertex = gpu::Shader::createVertex(std::string(model_normal_map_vert)); @@ -198,6 +132,8 @@ void initDeferredPipelines(render::ShapePlumber& plumber) { auto modelLightmapSpecularMapPixel = gpu::Shader::createPixel(std::string(model_lightmap_specular_map_frag)); auto modelLightmapNormalSpecularMapPixel = gpu::Shader::createPixel(std::string(model_lightmap_normal_specular_map_frag)); + using Key = render::ShapeKey; + auto addPipeline = std::bind(&addPlumberPipeline, std::ref(plumber), _1, _2, _3); // TODO: Refactor this to use a filter // Opaques addPipeline( @@ -281,5 +217,132 @@ void initDeferredPipelines(render::ShapePlumber& plumber) { addPipeline( Key::Builder().withSkinned().withDepthOnly(), skinModelShadowVertex, modelShadowPixel); - +} + +void initForwardPipelines(render::ShapePlumber& plumber) { + // Vertex shaders + auto modelVertex = gpu::Shader::createVertex(std::string(model_vert)); + auto modelNormalMapVertex = gpu::Shader::createVertex(std::string(model_normal_map_vert)); + auto skinModelVertex = gpu::Shader::createVertex(std::string(skin_model_vert)); + auto skinModelNormalMapVertex = gpu::Shader::createVertex(std::string(skin_model_normal_map_vert)); + + // Pixel shaders + auto modelPixel = gpu::Shader::createPixel(std::string(model_frag)); + auto modelUnlitPixel = gpu::Shader::createPixel(std::string(model_unlit_frag)); + auto modelNormalMapPixel = gpu::Shader::createPixel(std::string(model_normal_map_frag)); + auto modelSpecularMapPixel = gpu::Shader::createPixel(std::string(model_specular_map_frag)); + auto modelNormalSpecularMapPixel = gpu::Shader::createPixel(std::string(model_normal_specular_map_frag)); + + using Key = render::ShapeKey; + auto addPipeline = std::bind(&addPlumberPipeline, std::ref(plumber), _1, _2, _3); + // Opaques + addPipeline( + Key::Builder(), + modelVertex, modelPixel); + addPipeline( + Key::Builder().withUnlit(), + modelVertex, modelUnlitPixel); + addPipeline( + Key::Builder().withTangents(), + modelNormalMapVertex, modelNormalMapPixel); + addPipeline( + Key::Builder().withSpecular(), + modelVertex, modelSpecularMapPixel); + addPipeline( + Key::Builder().withTangents().withSpecular(), + modelNormalMapVertex, modelNormalSpecularMapPixel); + // Skinned + addPipeline( + Key::Builder().withSkinned(), + skinModelVertex, modelPixel); + addPipeline( + Key::Builder().withSkinned().withTangents(), + skinModelNormalMapVertex, modelNormalMapPixel); + addPipeline( + Key::Builder().withSkinned().withSpecular(), + skinModelVertex, modelSpecularMapPixel); + addPipeline( + Key::Builder().withSkinned().withTangents().withSpecular(), + skinModelNormalMapVertex, modelNormalSpecularMapPixel); +} + +void addPlumberPipeline(ShapePlumber& plumber, + const ShapeKey& key, const gpu::ShaderPointer& vertex, const gpu::ShaderPointer& pixel) { + // These key-values' pipelines are added by this functor in addition to the key passed + assert(!key.isWireFrame()); + assert(!key.isDepthBiased()); + assert(key.isCullFace()); + + gpu::ShaderPointer program = gpu::Shader::createProgram(vertex, pixel); + + for (int i = 0; i < 8; i++) { + bool isCulled = (i & 1); + bool isBiased = (i & 2); + bool isWireframed = (i & 4); + + auto state = std::make_shared(); + + // Depth test depends on transparency + state->setDepthTest(true, !key.isTranslucent(), gpu::LESS_EQUAL); + state->setBlendFunction(key.isTranslucent(), + gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, + gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); + + ShapeKey::Builder builder(key); + if (!isCulled) { + builder.withoutCullFace(); + } + state->setCullMode(isCulled ? gpu::State::CULL_BACK : gpu::State::CULL_NONE); + if (isWireframed) { + builder.withWireframe(); + state->setFillMode(gpu::State::FILL_LINE); + } + if (isBiased) { + builder.withDepthBias(); + state->setDepthBias(1.0f); + state->setDepthBiasSlopeScale(1.0f); + } + + plumber.addPipeline(builder.build(), program, state, + key.isTranslucent() ? &lightBatchSetter : &batchSetter); + } +} + +void batchSetter(const ShapePipeline& pipeline, gpu::Batch& batch) { + // Set a default albedo map + batch.setResourceTexture(render::ShapePipeline::Slot::MAP::ALBEDO, + DependencyManager::get()->getWhiteTexture()); + // Set a default normal map + batch.setResourceTexture(render::ShapePipeline::Slot::MAP::NORMAL_FITTING, + DependencyManager::get()->getNormalFittingTexture()); + + // Set a default material + if (pipeline.locations->materialBufferUnit >= 0) { + // Create a default schema + static bool isMaterialSet = false; + static model::Material material; + if (!isMaterialSet) { + material.setAlbedo(vec3(1.0f)); + material.setOpacity(1.0f); + material.setMetallic(0.1f); + material.setRoughness(0.9f); + isMaterialSet = true; + } + + // Set a default schema + batch.setUniformBuffer(ShapePipeline::Slot::BUFFER::MATERIAL, material.getSchemaBuffer()); + } +} + +void lightBatchSetter(const ShapePipeline& pipeline, gpu::Batch& batch) { + // Set the batch + batchSetter(pipeline, batch); + + // Set the light + if (pipeline.locations->lightBufferUnit >= 0) { + DependencyManager::get()->setupKeyLightBatch(batch, + pipeline.locations->lightBufferUnit, + pipeline.locations->lightAmbientBufferUnit, + pipeline.locations->lightAmbientMapUnit); + } } diff --git a/libraries/render-utils/src/nop.slf b/libraries/render-utils/src/nop.slf new file mode 100644 index 0000000000..f87db4e138 --- /dev/null +++ b/libraries/render-utils/src/nop.slf @@ -0,0 +1,16 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// nop.frag +// fragment shader +// +// Created by Zach Pomerantz on 1/3/2017. +// Copyright 2017 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 +// + +void main(void) { +} diff --git a/libraries/render/src/render/Task.h b/libraries/render/src/render/Task.h index 49273d79a5..4e3aa79c8d 100644 --- a/libraries/render/src/render/Task.h +++ b/libraries/render/src/render/Task.h @@ -371,6 +371,7 @@ protected: class JobConfig : public QObject { Q_OBJECT Q_PROPERTY(double cpuRunTime READ getCPURunTime NOTIFY newStats()) //ms + Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled) double _msCPURunTime{ 0.0 }; public: @@ -380,7 +381,7 @@ public: JobConfig(bool enabled) : alwaysEnabled{ false }, enabled{ enabled } {} bool isEnabled() { return alwaysEnabled || enabled; } - void setEnabled(bool enable) { enabled = enable; } + void setEnabled(bool enable) { enabled = alwaysEnabled || enable; } bool alwaysEnabled{ true }; bool enabled{ true };