// // 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 <PerfStat.h> #include <PathUtils.h> #include <RenderArgs.h> #include <ViewFrustum.h> #include <gpu/Context.h> #include "FramebufferCache.h" #include "TextureCache.h" #include <gpu/StandardShaderLib.h> #include "nop_frag.h" using namespace render; extern void initForwardPipelines(ShapePlumber& plumber); void RenderForwardTask::build(JobModel& task, const render::Varying& input, render::Varying& output) { auto items = input.get<Input>(); // Prepare the ShapePipelines ShapePlumberPointer shapePlumber = std::make_shared<ShapePlumber>(); initForwardPipelines(*shapePlumber); // Extract opaques / transparents / lights / metas / overlays / background const auto opaques = items[RenderFetchCullSortTask::OPAQUE_SHAPE]; const auto transparents = items[RenderFetchCullSortTask::TRANSPARENT_SHAPE]; const auto lights = items[RenderFetchCullSortTask::LIGHT]; const auto metas = items[RenderFetchCullSortTask::META]; const auto overlayOpaques = items[RenderFetchCullSortTask::OVERLAY_OPAQUE_SHAPE]; const auto overlayTransparents = items[RenderFetchCullSortTask::OVERLAY_TRANSPARENT_SHAPE]; const auto background = items[RenderFetchCullSortTask::BACKGROUND]; const auto spatialSelection = items[RenderFetchCullSortTask::SPATIAL_SELECTION]; const auto framebuffer = task.addJob<PrepareFramebuffer>("PrepareFramebuffer"); task.addJob<Draw>("DrawOpaques", opaques, shapePlumber); task.addJob<Stencil>("Stencil"); task.addJob<DrawBackground>("DrawBackground", background); // Bounds do not draw on stencil buffer, so they must come last task.addJob<DrawBounds>("DrawBounds", opaques); // Blit! task.addJob<Blit>("Blit", framebuffer); } void PrepareFramebuffer::run(const RenderContextPointer& renderContext, gpu::FramebufferPointer& framebuffer) { auto framebufferCache = DependencyManager::get<FramebufferCache>(); 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::Texture::create2D(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::create2D(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), 1.0, 0.0, true); }); framebuffer = _framebuffer; } void Draw::run(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(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<gpu::State>(); 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 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 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(renderContext, background); }); args->_batch = nullptr; }