From a9740b803fa91931e845615a8fbf5efad2c5f54d Mon Sep 17 00:00:00 2001 From: Bradley Austin Davis Date: Tue, 26 Jul 2016 16:13:48 -0700 Subject: [PATCH] Defer batch execution to the end of the frame generation --- interface/src/Application.cpp | 31 +++++++----- libraries/gpu/src/gpu/Batch.cpp | 27 +++++++++++ libraries/gpu/src/gpu/Context.cpp | 80 ++++++++++++++++++++++++------- libraries/gpu/src/gpu/Context.h | 73 +++++++++++----------------- libraries/gpu/src/gpu/Forward.h | 9 ++++ libraries/gpu/src/gpu/Frame.h | 1 + 6 files changed, 147 insertions(+), 74 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index eba400ebc5..e294ae38ad 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1689,6 +1689,17 @@ void Application::paintGL() { renderArgs._context->syncCache(); } + auto framebufferCache = DependencyManager::get(); + // Final framebuffer that will be handled to the display-plugin + auto finalFramebuffer = framebufferCache->getFramebuffer(); + + _gpuContext->beginFrame(finalFramebuffer, getHMDSensorPose()); + // Reset the gpu::Context Stages + // Back to the default framebuffer; + gpu::doInBatch(_gpuContext, [&](gpu::Batch& batch) { + batch.resetStages(); + }); + auto inputs = AvatarInputs::getInstance(); if (inputs->mirrorVisible()) { PerformanceTimer perfTimer("Mirror"); @@ -1711,10 +1722,6 @@ void Application::paintGL() { QSize size = getDeviceSize(); renderArgs._viewport = glm::ivec4(0, 0, size.width(), size.height()); _applicationOverlay.renderOverlay(&renderArgs); - auto overlayTexture = _applicationOverlay.acquireOverlay(); - if (overlayTexture) { - displayPlugin->submitOverlayTexture(overlayTexture); - } } glm::vec3 boomOffset; @@ -1816,12 +1823,8 @@ void Application::paintGL() { getApplicationCompositor().setFrameInfo(_frameCount, _myCamera.getTransform()); // Primary rendering pass - auto framebufferCache = DependencyManager::get(); const QSize size = framebufferCache->getFrameBufferSize(); - // Final framebuffer that will be handled to the display-plugin - auto finalFramebuffer = framebufferCache->getFramebuffer(); - { PROFILE_RANGE(__FUNCTION__ "/mainRender"); PerformanceTimer perfTimer("mainRender"); @@ -1880,6 +1883,13 @@ void Application::paintGL() { renderArgs._context->enableStereo(false); } + _gpuContext->endFrame(); + + gpu::TexturePointer overlayTexture = _applicationOverlay.acquireOverlay(); + if (overlayTexture) { + displayPlugin->submitOverlayTexture(overlayTexture); + } + // deliver final composited scene to the display plugin { PROFILE_RANGE(__FUNCTION__ "/pluginOutput"); @@ -1900,11 +1910,6 @@ void Application::paintGL() { { Stats::getInstance()->setRenderDetails(renderArgs._details); - // Reset the gpu::Context Stages - // Back to the default framebuffer; - gpu::doInBatch(renderArgs._context, [&](gpu::Batch& batch) { - batch.resetStages(); - }); } uint64_t lastPaintDuration = usecTimestampNow() - lastPaintBegin; diff --git a/libraries/gpu/src/gpu/Batch.cpp b/libraries/gpu/src/gpu/Batch.cpp index 9161ee3642..ab1337070c 100644 --- a/libraries/gpu/src/gpu/Batch.cpp +++ b/libraries/gpu/src/gpu/Batch.cpp @@ -46,6 +46,33 @@ Batch::Batch() { _drawCallInfos.reserve(_drawCallInfosMax); } +Batch::Batch(const Batch& batch_) { + Batch& batch = *const_cast(&batch_); + _commands.swap(batch._commands); + _commandOffsets.swap(batch._commandOffsets); + _params.swap(batch._params); + _data.swap(batch._data); + _invalidModel = batch._invalidModel; + _currentModel = batch._currentModel; + _objects.swap(batch._objects); + _currentNamedCall = batch._currentNamedCall; + + _buffers._items.swap(batch._buffers._items); + _textures._items.swap(batch._textures._items); + _streamFormats._items.swap(batch._streamFormats._items); + _transforms._items.swap(batch._transforms._items); + _pipelines._items.swap(batch._pipelines._items); + _framebuffers._items.swap(batch._framebuffers._items); + _drawCallInfos.swap(batch._drawCallInfos); + _queries._items.swap(batch._queries._items); + _lambdas._items.swap(batch._lambdas._items); + _profileRanges._items.swap(batch._profileRanges._items); + _names._items.swap(batch._names._items); + _namedData.swap(batch._namedData); + _enableStereo = batch._enableStereo; + _enableSkybox = batch._enableSkybox; +} + Batch::~Batch() { _commandsMax = std::max(_commands.size(), _commandsMax); _commandOffsetsMax = std::max(_commandOffsets.size(), _commandOffsetsMax); diff --git a/libraries/gpu/src/gpu/Context.cpp b/libraries/gpu/src/gpu/Context.cpp index 2c27260331..ff43491133 100644 --- a/libraries/gpu/src/gpu/Context.cpp +++ b/libraries/gpu/src/gpu/Context.cpp @@ -9,7 +9,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // #include "Context.h" - +#include "Frame.h" using namespace gpu; Context::CreateBackend Context::_createBackendCallback = nullptr; @@ -20,6 +20,13 @@ Context::Context() { if (_createBackendCallback) { _backend.reset(_createBackendCallback()); } + + _frameHandler = [this](Frame& frame){ + for (size_t i = 0; i < frame.batches.size(); ++i) { + _backend->_stereo = frame.stereoStates[i]; + _backend->render(frame.batches[i]); + } + }; } Context::Context(const Context& context) { @@ -28,6 +35,43 @@ Context::Context(const Context& context) { Context::~Context() { } +void Context::setFrameHandler(FrameHandler handler) { + _frameHandler = handler; +} + +#define DEFERRED_RENDERING + +void Context::beginFrame(const FramebufferPointer& outputFramebuffer, const glm::mat4& renderPose) { + _currentFrame = Frame(); + _currentFrame.framebuffer = outputFramebuffer; + _currentFrame.pose = renderPose; + _frameActive = true; +} + +void Context::append(Batch& batch) { + if (!_frameActive) { + qWarning() << "Batch executed outside of frame boundaries"; + } +#ifdef DEFERRED_RENDERING + _currentFrame.batches.emplace_back(batch); + _currentFrame.stereoStates.emplace_back(_stereo); +#else + _backend->_stereo = _stereo; + _backend->render(batch); +#endif +} + +void Context::endFrame() { +#ifdef DEFERRED_RENDERING + if (_frameHandler) { + _frameHandler(_currentFrame); + } +#endif + _currentFrame = Frame(); + _frameActive = false; +} + + bool Context::makeProgram(Shader& shader, const Shader::BindingSet& bindings) { if (shader.isProgram() && _makeProgramCallback) { return _makeProgramCallback(shader, bindings); @@ -35,36 +79,38 @@ bool Context::makeProgram(Shader& shader, const Shader::BindingSet& bindings) { return false; } -void Context::render(Batch& batch) { - PROFILE_RANGE(__FUNCTION__); - _backend->render(batch); -} - void Context::enableStereo(bool enable) { - _backend->enableStereo(enable); + _stereo._enable = enable; } bool Context::isStereo() { - return _backend->isStereo(); + return _stereo._enable; } void Context::setStereoProjections(const mat4 eyeProjections[2]) { - _backend->setStereoProjections(eyeProjections); + for (int i = 0; i < 2; ++i) { + _stereo._eyeProjections[i] = eyeProjections[i]; + } } -void Context::setStereoViews(const mat4 eyeViews[2]) { - _backend->setStereoViews(eyeViews); +void Context::setStereoViews(const mat4 views[2]) { + for (int i = 0; i < 2; ++i) { + _stereo._eyeViews[i] = views[i]; + } } void Context::getStereoProjections(mat4* eyeProjections) const { - _backend->getStereoProjections(eyeProjections); + for (int i = 0; i < 2; ++i) { + eyeProjections[i] = _stereo._eyeProjections[i]; + } } void Context::getStereoViews(mat4* eyeViews) const { - _backend->getStereoViews(eyeViews); + for (int i = 0; i < 2; ++i) { + eyeViews[i] = _stereo._eyeViews[i]; + } } - void Context::syncCache() { PROFILE_RANGE(__FUNCTION__); _backend->syncCache(); @@ -103,12 +149,12 @@ Backend::TransformCamera Backend::TransformCamera::getEyeCamera(int eye, const S if (!_stereo._skybox) { offsetTransform.postTranslate(-Vec3(_stereo._eyeViews[eye][3])); } else { - // FIXME: If "skybox" the ipd is set to 0 for now, let s try to propose a better solution for this in the future + // FIXME: If "skybox" the ipd is set to 0 for now, let s try to propose a better solution for this in the future } result._projection = _stereo._eyeProjections[eye]; result.recomputeDerived(offsetTransform); - result._stereoInfo = Vec4(1.0f, (float) eye, 0.0f, 0.0f); + result._stereoInfo = Vec4(1.0f, (float)eye, 0.0f, 0.0f); return result; } @@ -125,7 +171,7 @@ std::atomic Context::_textureGPUTransferCount{ 0 }; void Context::incrementBufferGPUCount() { _bufferGPUCount++; } -void Context::decrementBufferGPUCount() { +void Context::decrementBufferGPUCount() { _bufferGPUCount--; } void Context::updateBufferGPUMemoryUsage(Size prevObjectSize, Size newObjectSize) { diff --git a/libraries/gpu/src/gpu/Context.h b/libraries/gpu/src/gpu/Context.h index 2d0baa0497..5f894318f2 100644 --- a/libraries/gpu/src/gpu/Context.h +++ b/libraries/gpu/src/gpu/Context.h @@ -16,12 +16,13 @@ #include +#include "Forward.h" #include "Batch.h" - #include "Resource.h" #include "Texture.h" #include "Pipeline.h" #include "Framebuffer.h" +#include "Frame.h" class QImage; @@ -46,51 +47,11 @@ public: ContextStats(const ContextStats& stats) = default; }; -struct StereoState { - bool _enable{ false }; - bool _skybox{ false }; - // 0 for left eye, 1 for right eye - uint8_t _pass{ 0 }; - mat4 _eyeViews[2]; - mat4 _eyeProjections[2]; -}; - class Backend { public: virtual~ Backend() {}; virtual void render(Batch& batch) = 0; - virtual void enableStereo(bool enable) { - _stereo._enable = enable; - } - - virtual bool isStereo() { - return _stereo._enable; - } - - void setStereoProjections(const mat4 eyeProjections[2]) { - for (int i = 0; i < 2; ++i) { - _stereo._eyeProjections[i] = eyeProjections[i]; - } - } - - void setStereoViews(const mat4 views[2]) { - for (int i = 0; i < 2; ++i) { - _stereo._eyeViews[i] = views[i]; - } - } - - void getStereoProjections(mat4* eyeProjections) const { - for (int i = 0; i < 2; ++i) { - eyeProjections[i] = _stereo._eyeProjections[i]; - } - } - - void getStereoViews(mat4* eyeViews) const { - for (int i = 0; i < 2; ++i) { - eyeViews[i] = _stereo._eyeViews[i]; - } - } virtual void syncCache() = 0; virtual void downloadFramebuffer(const FramebufferPointer& srcFramebuffer, const Vec4i& region, QImage& destImage) = 0; @@ -137,8 +98,25 @@ public: static void decrementTextureGPUTransferCount(); protected: - StereoState _stereo; + virtual bool isStereo() { + return _stereo._enable; + } + + void getStereoProjections(mat4* eyeProjections) const { + for (int i = 0; i < 2; ++i) { + eyeProjections[i] = _stereo._eyeProjections[i]; + } + } + + void getStereoViews(mat4* eyeViews) const { + for (int i = 0; i < 2; ++i) { + eyeViews[i] = _stereo._eyeViews[i]; + } + } + + friend class Context; ContextStats _stats; + StereoState _stereo; }; class Context { @@ -161,7 +139,10 @@ public: Context(); ~Context(); - void render(Batch& batch); + void setFrameHandler(FrameHandler handler); + void beginFrame(const FramebufferPointer& outputFramebuffer, const glm::mat4& renderPose = glm::mat4()); + void append(Batch& batch); + void endFrame(); void enableStereo(bool enable = true); bool isStereo(); @@ -191,6 +172,10 @@ protected: Context(const Context& context); std::unique_ptr _backend; + bool _frameActive { false }; + Frame _currentFrame; + FrameHandler _frameHandler; + StereoState _stereo; // This function can only be called by "static Shader::makeProgram()" // makeProgramShader(...) make a program shader ready to be used in a Batch. @@ -234,7 +219,7 @@ template void doInBatch(std::shared_ptr context, F f) { gpu::Batch batch; f(batch); - context->render(batch); + context->append(batch); } }; diff --git a/libraries/gpu/src/gpu/Forward.h b/libraries/gpu/src/gpu/Forward.h index e2a4ad38dd..3b04b17d87 100644 --- a/libraries/gpu/src/gpu/Forward.h +++ b/libraries/gpu/src/gpu/Forward.h @@ -86,6 +86,15 @@ namespace gpu { class TextureView; using TextureViews = std::vector; + struct StereoState { + bool _enable{ false }; + bool _skybox{ false }; + // 0 for left eye, 1 for right eye + uint8 _pass{ 0 }; + Mat4 _eyeViews[2]; + Mat4 _eyeProjections[2]; + }; + namespace gl { class GLBuffer; } diff --git a/libraries/gpu/src/gpu/Frame.h b/libraries/gpu/src/gpu/Frame.h index 99296cc91e..ed5e2ea179 100644 --- a/libraries/gpu/src/gpu/Frame.h +++ b/libraries/gpu/src/gpu/Frame.h @@ -18,6 +18,7 @@ public: glm::mat4 pose; /// The collection of batches which make up the frame std::vector batches; + std::vector stereoStates; /// The destination framebuffer in which the results will be placed FramebufferPointer framebuffer; };