// // 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 #include #include #include #include #include #include "StencilMaskPass.h" #include "ZoneRenderer.h" #include "FadeEffect.h" #include "BackgroundStage.h" #include "FramebufferCache.h" #include "TextureCache.h" #include "RenderCommonTask.h" #include "LightStage.h" #include "nop_frag.h" using namespace render; extern void initForwardPipelines(ShapePlumber& plumber, const render::ShapePipeline::BatchSetter& batchSetter, const render::ShapePipeline::ItemSetter& itemSetter); void RenderForwardTask::build(JobModel& task, const render::Varying& input, render::Varying& output) { auto items = input.get(); auto fadeEffect = DependencyManager::get(); // Prepare the ShapePipelines ShapePlumberPointer shapePlumber = std::make_shared(); initForwardPipelines(*shapePlumber, fadeEffect->getBatchSetter(), fadeEffect->getItemUniformSetter()); // Extract opaques / transparents / lights / metas / overlays / background const auto& opaques = items.get0()[RenderFetchCullSortTask::OPAQUE_SHAPE]; const auto& transparents = items.get0()[RenderFetchCullSortTask::TRANSPARENT_SHAPE]; // const auto& lights = items.get0()[RenderFetchCullSortTask::LIGHT]; const auto& metas = items.get0()[RenderFetchCullSortTask::META]; // const auto& overlayOpaques = items.get0()[RenderFetchCullSortTask::OVERLAY_OPAQUE_SHAPE]; // const auto& overlayTransparents = items.get0()[RenderFetchCullSortTask::OVERLAY_TRANSPARENT_SHAPE]; //const auto& background = items.get0()[RenderFetchCullSortTask::BACKGROUND]; // const auto& spatialSelection = items[1]; fadeEffect->build(task, opaques); // Prepare objects shared by several jobs const auto lightingModel = task.addJob("LightingModel"); // Filter zones from the general metas bucket const auto zones = task.addJob("ZoneRenderer", metas); // GPU jobs: Start preparing the main framebuffer const auto framebuffer = task.addJob("PrepareFramebuffer"); task.addJob("PrepareForward", lightingModel); // draw a stencil mask in hidden regions of the framebuffer. task.addJob("PrepareStencil", framebuffer); // Draw opaques forward const auto opaqueInputs = DrawForward::Inputs(opaques, lightingModel).asVarying(); task.addJob("DrawOpaques", opaqueInputs, shapePlumber); // Similar to light stage, background stage has been filled by several potential render items and resolved for the frame in this job task.addJob("DrawBackgroundDeferred", lightingModel); // Draw transparent objects forward const auto transparentInputs = DrawForward::Inputs(transparents, lightingModel).asVarying(); task.addJob("DrawTransparents", transparentInputs, shapePlumber); { // Debug the bounds of the rendered items, still look at the zbuffer task.addJob("DrawMetaBounds", metas); task.addJob("DrawBounds", opaques); task.addJob("DrawTransparentBounds", transparents); task.addJob("DrawZones", zones); } // Layered Overlays // Composite the HUD and HUD overlays task.addJob("HUD"); // Blit! task.addJob("Blit", framebuffer); } void PrepareFramebuffer::run(const RenderContextPointer& renderContext, gpu::FramebufferPointer& framebuffer) { glm::uvec2 frameSize(renderContext->args->_viewport.z, renderContext->args->_viewport.w); // 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::Texture::createRenderBuffer(colorFormat, frameSize.x, frameSize.y, gpu::Texture::SINGLE_MIP, defaultSampler); _framebuffer->setRenderBuffer(0, colorTexture); auto depthFormat = gpu::Element(gpu::SCALAR, gpu::UINT32, gpu::DEPTH_STENCIL); // Depth24_Stencil8 texel format auto depthTexture = gpu::Texture::createRenderBuffer(depthFormat, frameSize.x, frameSize.y, gpu::Texture::SINGLE_MIP, 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_DEPTH | gpu::Framebuffer::BUFFER_STENCIL, vec4(vec3(0, 1.0, 0.0), 0), 1.0, 0, true); }); framebuffer = _framebuffer; } enum ForwardShader_MapSlot { DEFERRED_BUFFER_COLOR_UNIT = 0, DEFERRED_BUFFER_NORMAL_UNIT = 1, DEFERRED_BUFFER_EMISSIVE_UNIT = 2, DEFERRED_BUFFER_DEPTH_UNIT = 3, DEFERRED_BUFFER_OBSCURANCE_UNIT = 4, SHADOW_MAP_UNIT = 5, SKYBOX_MAP_UNIT = SHADOW_MAP_UNIT + 4, DEFERRED_BUFFER_LINEAR_DEPTH_UNIT, DEFERRED_BUFFER_CURVATURE_UNIT, DEFERRED_BUFFER_DIFFUSED_CURVATURE_UNIT, SCATTERING_LUT_UNIT, SCATTERING_SPECULAR_UNIT, }; enum ForwardShader_BufferSlot { DEFERRED_FRAME_TRANSFORM_BUFFER_SLOT = 0, CAMERA_CORRECTION_BUFFER_SLOT, SCATTERING_PARAMETERS_BUFFER_SLOT, LIGHTING_MODEL_BUFFER_SLOT = render::ShapePipeline::Slot::LIGHTING_MODEL, LIGHT_GPU_SLOT = render::ShapePipeline::Slot::LIGHT, LIGHT_AMBIENT_SLOT = render::ShapePipeline::Slot::LIGHT_AMBIENT_BUFFER, HAZE_MODEL_BUFFER_SLOT = render::ShapePipeline::Slot::HAZE_MODEL, LIGHT_INDEX_GPU_SLOT, LIGHT_CLUSTER_GRID_FRUSTUM_GRID_SLOT, LIGHT_CLUSTER_GRID_CLUSTER_GRID_SLOT, LIGHT_CLUSTER_GRID_CLUSTER_CONTENT_SLOT, }; void PrepareForward::run(const RenderContextPointer& renderContext, const Inputs& inputs) { RenderArgs* args = renderContext->args; gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { args->_batch = &batch; graphics::LightPointer keySunLight; auto lightStage = args->_scene->getStage(); if (lightStage) { keySunLight = lightStage->getCurrentKeyLight(); } graphics::LightPointer keyAmbiLight; if (lightStage) { keyAmbiLight = lightStage->getCurrentAmbientLight(); } if (keySunLight) { if (LIGHT_GPU_SLOT >= 0) { batch.setUniformBuffer(LIGHT_GPU_SLOT, keySunLight->getLightSchemaBuffer()); } } if (keyAmbiLight) { if (LIGHT_AMBIENT_SLOT >= 0) { batch.setUniformBuffer(LIGHT_AMBIENT_SLOT, keyAmbiLight->getAmbientSchemaBuffer()); } if (keyAmbiLight->getAmbientMap() && (SKYBOX_MAP_UNIT >= 0)) { batch.setResourceTexture(SKYBOX_MAP_UNIT, keyAmbiLight->getAmbientMap()); } } }); } void DrawForward::run(const RenderContextPointer& renderContext, const Inputs& inputs) { RenderArgs* args = renderContext->args; const auto& inItems = inputs.get0(); const auto& lightingModel = inputs.get1(); 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()); // Setup lighting model for all items; batch.setUniformBuffer(render::ShapePipeline::Slot::LIGHTING_MODEL, lightingModel->getParametersBuffer()); // From the lighting model define a global shapeKey ORED with individiual keys ShapeKey::Builder keyBuilder; if (lightingModel->isWireframeEnabled()) { keyBuilder.withWireframe(); } ShapeKey globalKey = keyBuilder.build(); args->_globalShapeKey = globalKey._flags.to_ulong(); // Render items renderStateSortShapes(renderContext, _shapePlumber, inItems, -1, globalKey); args->_batch = nullptr; args->_globalShapeKey = 0; }); }