diff --git a/libraries/gpu/src/gpu/State.h b/libraries/gpu/src/gpu/State.h index abe0cd7731..2e8a3f2cab 100755 --- a/libraries/gpu/src/gpu/State.h +++ b/libraries/gpu/src/gpu/State.h @@ -246,7 +246,7 @@ public: struct Flags { Flags() : - frontFaceClockwise(false), depthClampEnable(false), scissorEnable(false), multisampleEnable(false), + frontFaceClockwise(false), depthClampEnable(false), scissorEnable(false), multisampleEnable(true), antialisedLineEnable(true), alphaToCoverageEnable(false), _spare1(0) {} bool frontFaceClockwise : 1; bool depthClampEnable : 1; diff --git a/libraries/render-utils/src/RenderCommonTask.cpp b/libraries/render-utils/src/RenderCommonTask.cpp index 64037d64b6..385e384efe 100644 --- a/libraries/render-utils/src/RenderCommonTask.cpp +++ b/libraries/render-utils/src/RenderCommonTask.cpp @@ -101,7 +101,7 @@ void DrawLayered3D::run(const RenderContextPointer& renderContext, const Inputs& } } -void CompositeHUD::run(const RenderContextPointer& renderContext) { +void CompositeHUD::run(const RenderContextPointer& renderContext, const gpu::FramebufferPointer& inputs) { assert(renderContext->args); assert(renderContext->args->_context); @@ -119,6 +119,9 @@ void CompositeHUD::run(const RenderContextPointer& renderContext) { renderContext->args->getViewFrustum().evalViewTransform(viewMat); batch.setProjectionTransform(projMat); batch.setViewTransform(viewMat, true); + if (inputs) { + batch.setFramebuffer(inputs); + } if (renderContext->args->_hudOperator) { renderContext->args->_hudOperator(batch, renderContext->args->_hudTexture, renderContext->args->_renderMode == RenderArgs::RenderMode::MIRROR_RENDER_MODE); } @@ -197,7 +200,73 @@ void Blit::run(const RenderContextPointer& renderContext, const gpu::Framebuffer }); } -void ExtractFrustums::run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& output) { + +void ResolveFramebuffer::run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs) { + RenderArgs* args = renderContext->args; + auto srcFbo = inputs.get0(); + auto destFbo = inputs.get1(); + + if (!destFbo) { + destFbo = args->_blitFramebuffer; + } + outputs = destFbo; + + // Check valid src and dest + if (!srcFbo || !destFbo) { + return; + } + + // Check valid size for sr and dest + auto frameSize(srcFbo->getSize()); + if (destFbo->getSize() != frameSize) { + return; + } + + gpu::Vec4i rectSrc; + rectSrc.z = frameSize.x; + rectSrc.w = frameSize.y; + gpu::doInBatch("Resolve", args->_context, [&](gpu::Batch& batch) { + batch.blit(srcFbo, rectSrc, destFbo, rectSrc); + }); +} + +void ResolveNewFramebuffer::run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs) { + RenderArgs* args = renderContext->args; + auto srcFbo = inputs; + outputs.reset(); + + // Check valid src + if (!srcFbo) { + return; + } + + // Check valid size for sr and dest + auto frameSize(srcFbo->getSize()); + + // Resizing framebuffers instead of re-building them seems to cause issues with threaded rendering + if (_outputFramebuffer && _outputFramebuffer->getSize() != frameSize) { + _outputFramebuffer.reset(); + } + + if (!_outputFramebuffer) { + _outputFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("resolvedNew.out")); + auto colorFormat = gpu::Element::COLOR_SRGBA_32; + auto defaultSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR); + auto colorTexture = gpu::Texture::createRenderBuffer(colorFormat, frameSize.x, frameSize.y, gpu::Texture::SINGLE_MIP, defaultSampler); + _outputFramebuffer->setRenderBuffer(0, colorTexture); + } + + gpu::Vec4i rectSrc; + rectSrc.z = frameSize.x; + rectSrc.w = frameSize.y; + gpu::doInBatch("ResolveNew", args->_context, [&](gpu::Batch& batch) { batch.blit(srcFbo, rectSrc, _outputFramebuffer, rectSrc); }); + + outputs = _outputFramebuffer; +} + + + + void ExtractFrustums::run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& output) { assert(renderContext->args); assert(renderContext->args->_context); diff --git a/libraries/render-utils/src/RenderCommonTask.h b/libraries/render-utils/src/RenderCommonTask.h index 4f8f53257d..b43a10aa7b 100644 --- a/libraries/render-utils/src/RenderCommonTask.h +++ b/libraries/render-utils/src/RenderCommonTask.h @@ -77,10 +77,12 @@ protected: class CompositeHUD { public: - using JobModel = render::Job::Model; + // IF specified the input Framebuffer is actively set by the batch of this job before calling the HUDOperator. + // If not, the current Framebuffer is left unchanged. + //using Inputs = gpu::FramebufferPointer; + using JobModel = render::Job::ModelI; - CompositeHUD() {} - void run(const render::RenderContextPointer& renderContext); + void run(const render::RenderContextPointer& renderContext, const gpu::FramebufferPointer& inputs); }; class Blit { @@ -90,6 +92,28 @@ public: void run(const render::RenderContextPointer& renderContext, const gpu::FramebufferPointer& srcFramebuffer); }; + +class ResolveFramebuffer { +public: + using Inputs = render::VaryingSet2; + using Outputs = gpu::FramebufferPointer; + using JobModel = render::Job::ModelIO; + + void run(const render::RenderContextPointer& renderContext, const Inputs& source, Outputs& dest); +}; + +class ResolveNewFramebuffer { +public: + using Inputs = gpu::FramebufferPointer; + using Outputs = gpu::FramebufferPointer; + using JobModel = render::Job::ModelIO; + + void run(const render::RenderContextPointer& renderContext, const Inputs& source, Outputs& dest); +private: + gpu::FramebufferPointer _outputFramebuffer; +}; + + class ExtractFrustums { public: diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 673a165105..089d267711 100644 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -257,8 +257,8 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren // Upscale to finale resolution const auto primaryFramebuffer = task.addJob("PrimaryBufferUpscale", scaledPrimaryFramebuffer); - // Composite the HUD and HUD layered objects - task.addJob("HUD"); + // Composite the HUD and HUD overlays + task.addJob("HUD", primaryFramebuffer); const auto nullJitter = Varying(glm::vec2(0.0f, 0.0f)); const auto hudOpaquesInputs = DrawLayered3D::Inputs(hudOpaque, lightingModel, nullJitter).asVarying(); diff --git a/libraries/render-utils/src/RenderForwardTask.cpp b/libraries/render-utils/src/RenderForwardTask.cpp index b7078a00a7..df82d4b56d 100755 --- a/libraries/render-utils/src/RenderForwardTask.cpp +++ b/libraries/render-utils/src/RenderForwardTask.cpp @@ -126,14 +126,24 @@ void RenderForwardTask::build(JobModel& task, const render::Varying& input, rend task.addJob("DrawZoneStack", debugZoneInputs); } + // Just resolve the msaa + const auto resolveInputs = + ResolveFramebuffer::Inputs(framebuffer, static_cast(nullptr)).asVarying(); + const auto resolvedFramebuffer = task.addJob("Resolve", resolveInputs); + //auto resolvedFramebuffer = task.addJob("Resolve", framebuffer); + +#if defined(Q_OS_ANDROID) +#else // Lighting Buffer ready for tone mapping // Forward rendering on GLES doesn't support tonemapping to and from the same FBO, so we specify // the output FBO as null, which causes the tonemapping to target the blit framebuffer - const auto toneMappingInputs = ToneMappingDeferred::Inputs(framebuffer, static_cast(nullptr) ).asVarying(); + const auto toneMappingInputs = ToneMappingDeferred::Inputs(resolvedFramebuffer, static_cast(nullptr)).asVarying(); task.addJob("ToneMapping", toneMappingInputs); +#endif - // Composite the HUD and HUD layered objects - task.addJob("HUD"); + // Layered Overlays + // Composite the HUD and HUD overlays + task.addJob("HUD", resolvedFramebuffer); const auto hudOpaquesInputs = DrawLayered3D::Inputs(hudOpaque, lightingModel, nullJitter).asVarying(); const auto hudTransparentsInputs = DrawLayered3D::Inputs(hudTransparent, lightingModel, nullJitter).asVarying(); @@ -145,26 +155,32 @@ void RenderForwardTask::build(JobModel& task, const render::Varying& input, rend // task.addJob("Blit", framebuffer); } +void PrepareFramebuffer::configure(const Config& config) { + _numSamples = config.getNumSamples(); +} + 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) { + if (_framebuffer && (_framebuffer->getSize() != frameSize || _framebuffer->getNumSamples() != _numSamples)) { _framebuffer.reset(); } if (!_framebuffer) { _framebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("forward")); + int numSamples = _numSamples; + auto colorFormat = gpu::Element::COLOR_SRGBA_32; - auto defaultSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_POINT); + auto defaultSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR); auto colorTexture = - gpu::Texture::createRenderBuffer(colorFormat, frameSize.x, frameSize.y, gpu::Texture::SINGLE_MIP, defaultSampler); + gpu::Texture::createRenderBufferMultisample(colorFormat, frameSize.x, frameSize.y, numSamples, 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); + gpu::Texture::createRenderBufferMultisample(depthFormat, frameSize.x, frameSize.y, numSamples, defaultSampler); _framebuffer->setDepthStencilBuffer(depthTexture, depthFormat); } diff --git a/libraries/render-utils/src/RenderForwardTask.h b/libraries/render-utils/src/RenderForwardTask.h index e6a6008319..85b51ad5fa 100755 --- a/libraries/render-utils/src/RenderForwardTask.h +++ b/libraries/render-utils/src/RenderForwardTask.h @@ -27,16 +27,37 @@ public: void build(JobModel& task, const render::Varying& input, render::Varying& output); }; + +class PrepareFramebufferConfig : public render::Job::Config { + Q_OBJECT + Q_PROPERTY(int numSamples WRITE setNumSamples READ getNumSamples NOTIFY dirty) +public: + int getNumSamples() const { return numSamples; } + void setNumSamples(int num) { + numSamples = std::max(1, std::min(32, num)); + emit dirty(); + } + +signals: + void dirty(); + +protected: + int numSamples{ 4 }; +}; + class PrepareFramebuffer { public: using Inputs = gpu::FramebufferPointer; - using JobModel = render::Job::ModelO; + using Config = PrepareFramebufferConfig; + using JobModel = render::Job::ModelO; + void configure(const Config& config); void run(const render::RenderContextPointer& renderContext, gpu::FramebufferPointer& framebuffer); private: gpu::FramebufferPointer _framebuffer; + int _numSamples; }; class PrepareForward {