From 76f236adf61f4103298cb3d37beeff688161efbb Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Wed, 12 Aug 2015 22:44:16 -0700 Subject: [PATCH] New stereo rendering implementation --- interface/src/Application.cpp | 111 ++++++---------- interface/src/Stars.cpp | 4 +- interface/src/ui/ApplicationCompositor.cpp | 2 - interface/src/ui/ApplicationOverlay.cpp | 1 - .../src/display-plugins/DisplayPlugin.cpp | 2 +- .../src/display-plugins/DisplayPlugin.h | 4 + .../oculus/OculusBaseDisplayPlugin.cpp | 8 +- .../oculus/OculusBaseDisplayPlugin.h | 4 +- .../stereo/SideBySideStereoDisplayPlugin.cpp | 2 +- .../stereo/StereoDisplayPlugin.cpp | 12 +- .../stereo/StereoDisplayPlugin.h | 3 + libraries/gpu/src/gpu/Batch.cpp | 15 +++ libraries/gpu/src/gpu/Batch.h | 18 ++- libraries/gpu/src/gpu/Context.cpp | 35 +++++ libraries/gpu/src/gpu/Context.h | 44 ++++++- libraries/gpu/src/gpu/Forward.h | 77 +++++++++++ libraries/gpu/src/gpu/GLBackend.cpp | 80 ++++++------ libraries/gpu/src/gpu/GLBackend.h | 27 ++-- libraries/gpu/src/gpu/GLBackendOutput.cpp | 3 + libraries/gpu/src/gpu/GLBackendState.cpp | 6 + libraries/gpu/src/gpu/GLBackendTransform.cpp | 121 +++++++++++------- .../input-plugins/ViveControllerManager.cpp | 1 - .../src/AmbientOcclusionEffect.cpp | 1 - .../src/DeferredLightingEffect.cpp | 5 + .../render-utils/src/RenderDeferredTask.cpp | 65 ++++++---- libraries/render/src/render/DrawStatus.cpp | 5 +- libraries/render/src/render/DrawTask.cpp | 6 +- 27 files changed, 452 insertions(+), 210 deletions(-) create mode 100644 libraries/gpu/src/gpu/Forward.h diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index b9bafbab1a..68b2322394 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1058,29 +1058,18 @@ void Application::paintGL() { // Using the latter will cause the camera to wobble with idle animations, // or with changes from the face tracker renderArgs._renderMode = RenderArgs::DEFAULT_RENDER_MODE; - - if (!getActiveDisplayPlugin()->isHmd()) { - _myCamera.setPosition(_myAvatar->getDefaultEyePosition()); - _myCamera.setRotation(_myAvatar->getHead()->getCameraOrientation()); - } else { - mat4 camMat = _myAvatar->getSensorToWorldMatrix() * _myAvatar->getHMDSensorMatrix(); - _myCamera.setPosition(extractTranslation(camMat)); - _myCamera.setRotation(glm::quat_cast(camMat)); - } + _myCamera.setPosition(_myAvatar->getDefaultEyePosition()); + _myCamera.setRotation(_myAvatar->getOrientation()); } else if (_myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) { - if (isHMDMode()) { - _myCamera.setRotation(_myAvatar->getWorldAlignedOrientation()); - } else { - _myCamera.setRotation(_myAvatar->getHead()->getOrientation()); - } - if (Menu::getInstance()->isOptionChecked(MenuOption::CenterPlayerInView)) { - _myCamera.setPosition(_myAvatar->getDefaultEyePosition() + - _myCamera.getRotation() * glm::vec3(0.0f, 0.0f, 1.0f) * _myAvatar->getBoomLength() * _myAvatar->getScale()); - } else { - _myCamera.setPosition(_myAvatar->getDefaultEyePosition() + - _myAvatar->getOrientation() * glm::vec3(0.0f, 0.0f, 1.0f) * _myAvatar->getBoomLength() * _myAvatar->getScale()); - } + _myCamera.setRotation(_myAvatar->getOrientation()); + // https://www.youtube.com/watch?v=pFriRcIwqNU + vec3 boomStick = glm::vec3(0.0f, 0.0f, 1.0f) * _myAvatar->getBoomLength() * _myAvatar->getScale(); + quat boomRotation = _myAvatar->getOrientation(); + if (!isHMDMode() && Menu::getInstance()->isOptionChecked(MenuOption::CenterPlayerInView)) { + boomRotation = _myCamera.getRotation(); + } + _myCamera.setPosition(_myAvatar->getDefaultEyePosition() + boomRotation * boomStick); } else if (_myCamera.getMode() == CAMERA_MODE_MIRROR) { _myCamera.setRotation(_myAvatar->getWorldAlignedOrientation() * glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f))); _myCamera.setPosition(_myAvatar->getDefaultEyePosition() + @@ -1089,7 +1078,6 @@ void Application::paintGL() { glm::vec3(0.0f, 0.0f, -1.0f) * MIRROR_FULLSCREEN_DISTANCE * _scaleMirror); renderArgs._renderMode = RenderArgs::MIRROR_RENDER_MODE; } - // Update camera position if (!isHMDMode()) { _myCamera.update(1.0f / _fps); @@ -1105,57 +1093,37 @@ void Application::paintGL() { QSize size = DependencyManager::get()->getFrameBufferSize(); renderArgs._viewport = glm::ivec4(0, 0, size.width(), size.height()); - { - PROFILE_RANGE(__FUNCTION__ "/clear"); - doInBatch(&renderArgs, [&](gpu::Batch& batch) { - auto primaryFbo = DependencyManager::get()->getPrimaryFramebuffer(); - batch.setFramebuffer(primaryFbo); - // clear the normal and specular buffers - batch.clearFramebuffer( - gpu::Framebuffer::BUFFER_COLOR0 | - gpu::Framebuffer::BUFFER_COLOR1 | - gpu::Framebuffer::BUFFER_COLOR2 | - gpu::Framebuffer::BUFFER_DEPTH, - vec4(vec3(0), 1), 1.0, 0.0); - }); - } + doInBatch(&renderArgs, [&](gpu::Batch& batch) { + auto primaryFbo = DependencyManager::get()->getPrimaryFramebuffer(); + batch.setFramebuffer(primaryFbo); + // clear the normal and specular buffers + batch.clearFramebuffer( + gpu::Framebuffer::BUFFER_COLOR0 | + gpu::Framebuffer::BUFFER_COLOR1 | + gpu::Framebuffer::BUFFER_COLOR2 | + gpu::Framebuffer::BUFFER_DEPTH, + vec4(vec3(0), 1), 1.0, 0.0); + }); + renderArgs._viewport = gpu::Vec4i(0, 0, size.width(), size.height()); if (displayPlugin->isStereo()) { - PROFILE_RANGE(__FUNCTION__ "/stereoRender"); - QRect currentViewport(QPoint(0, 0), QSize(size.width() / 2, size.height())); - glEnable(GL_SCISSOR_TEST); - for_each_eye([&](Eye eye){ - // Load the view frustum, used by meshes - Camera eyeCamera; - if (qApp->isHMDMode()) { - // Allow the displayPlugin to compose the final eye transform, based on the most up-to-date head motion. - eyeCamera.setTransform(displayPlugin->getModelview(eye, _myAvatar->getSensorToWorldMatrix())); - } else { - eyeCamera.setTransform(displayPlugin->getModelview(eye, _myCamera.getTransform())); - } - eyeCamera.setProjection(displayPlugin->getProjection(eye, _myCamera.getProjection())); - renderArgs._viewport = toGlm(currentViewport); - doInBatch(&renderArgs, [&](gpu::Batch& batch) { - batch.setViewportTransform(renderArgs._viewport); - batch.setStateScissorRect(renderArgs._viewport); - }); - displaySide(&renderArgs, eyeCamera); - }, [&] { - currentViewport.moveLeft(currentViewport.width()); + //_myCamera.setProjection(displayPlugin->getProjection(Mono, _myCamera.getProjection())); + renderArgs._context->enableStereo(true); + mat4 eyeViews[2]; + mat4 eyeProjections[2]; + auto baseProjection = renderArgs._viewFrustum->getProjection(); + // FIXME we don't need to set these every frame, + // only when the display plugin changes + for_each_eye([&](Eye eye) { + eyeViews[eye] = displayPlugin->getModelview(eye, mat4()); + eyeProjections[eye] = displayPlugin->getProjection(eye, baseProjection); }); - glDisable(GL_SCISSOR_TEST); - } else { - PROFILE_RANGE(__FUNCTION__ "/monoRender"); - renderArgs._viewport = gpu::Vec4i(0, 0, size.width(), size.height()); - // Viewport is assigned to the size of the framebuffer - doInBatch(&renderArgs, [&](gpu::Batch& batch) { - batch.setViewportTransform(renderArgs._viewport); - batch.setStateScissorRect(renderArgs._viewport); - }); - displaySide(&renderArgs, _myCamera); + renderArgs._context->setStereoProjections(eyeProjections); + renderArgs._context->setStereoViews(eyeViews); } - - doInBatch(&renderArgs, [](gpu::Batch& batch){ + displaySide(&renderArgs, _myCamera); + renderArgs._context->enableStereo(false); + doInBatch(&renderArgs, [](gpu::Batch& batch) { batch.setFramebuffer(nullptr); }); } @@ -4997,6 +4965,11 @@ mat4 Application::getHMDSensorPose() const { return mat4(); } +// FIXME there is a bug in the fullscreen setting, where leaving +// fullscreen does not restore the window frame, making it difficult +// or impossible to move or size the window. +// Additionally, setting fullscreen isn't hiding the menu on windows +// make it useless for stereoscopic modes. void Application::setFullscreen(const QScreen* target) { if (!_window->isFullScreen()) { _savedGeometry = _window->geometry(); diff --git a/interface/src/Stars.cpp b/interface/src/Stars.cpp index 42b1a3f2e2..119b9ed1a2 100644 --- a/interface/src/Stars.cpp +++ b/interface/src/Stars.cpp @@ -191,7 +191,7 @@ void Stars::render(RenderArgs* renderArgs, float alpha) { auto geometryCache = DependencyManager::get(); auto textureCache = DependencyManager::get(); - gpu::Batch batch; + gpu::Batch& batch = *renderArgs->_batch; batch.setViewTransform(Transform()); batch.setProjectionTransform(renderArgs->_viewFrustum->getProjection()); batch.setModelTransform(Transform().setRotation(glm::inverse(renderArgs->_viewFrustum->getOrientation()) * @@ -219,6 +219,4 @@ void Stars::render(RenderArgs* renderArgs, float alpha) { batch.setInputBuffer(VERTICES_SLOT, posView); batch.setInputBuffer(COLOR_SLOT, colView); batch.draw(gpu::Primitive::POINTS, STARFIELD_NUM_STARS); - - renderArgs->_context->render(batch); } diff --git a/interface/src/ui/ApplicationCompositor.cpp b/interface/src/ui/ApplicationCompositor.cpp index abc1e49101..98634d7aed 100644 --- a/interface/src/ui/ApplicationCompositor.cpp +++ b/interface/src/ui/ApplicationCompositor.cpp @@ -211,7 +211,6 @@ void ApplicationCompositor::displayOverlayTexture(RenderArgs* renderArgs) { //Handle fading and deactivation/activation of UI gpu::Batch batch; - renderArgs->_context->syncCache(); auto geometryCache = DependencyManager::get(); geometryCache->useSimpleDrawPipeline(batch); @@ -279,7 +278,6 @@ void ApplicationCompositor::displayOverlayTextureHmd(RenderArgs* renderArgs, int vec2 canvasSize = qApp->getCanvasSize(); _textureAspectRatio = aspect(canvasSize); - renderArgs->_context->syncCache(); auto geometryCache = DependencyManager::get(); gpu::Batch batch; diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index 6f18cac127..7254295c2f 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -92,7 +92,6 @@ void ApplicationOverlay::renderOverlay(RenderArgs* renderArgs) { renderOverlays(renderArgs); // renders Scripts Overlay and AudioScope renderStatsAndLogs(renderArgs); // currently renders nothing - renderArgs->_context->syncCache(); renderArgs->_context->render(batch); renderArgs->_batch = nullptr; // so future users of renderArgs don't try to use our batch diff --git a/libraries/display-plugins/src/display-plugins/DisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/DisplayPlugin.cpp index 2316ff70c4..8bfe8c20da 100644 --- a/libraries/display-plugins/src/display-plugins/DisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/DisplayPlugin.cpp @@ -28,7 +28,7 @@ DisplayPluginList getDisplayPlugins() { // Stereo modes // FIXME fix stereo display plugins - //new SideBySideStereoDisplayPlugin(), + new SideBySideStereoDisplayPlugin(), //new InterleavedStereoDisplayPlugin(), // HMDs diff --git a/libraries/display-plugins/src/display-plugins/DisplayPlugin.h b/libraries/display-plugins/src/display-plugins/DisplayPlugin.h index 45a5923a1f..da3bc98135 100644 --- a/libraries/display-plugins/src/display-plugins/DisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/DisplayPlugin.h @@ -107,6 +107,10 @@ public: static const glm::mat4 pose; return pose; } + virtual glm::vec3 getEyeOffset(Eye eye) const { + static const glm::vec3 offset; return offset; + } + virtual glm::mat4 getHeadPose() const { static const glm::mat4 pose; return pose; } diff --git a/libraries/display-plugins/src/display-plugins/oculus/OculusBaseDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/oculus/OculusBaseDisplayPlugin.cpp index 7d0fb705df..0490e82106 100644 --- a/libraries/display-plugins/src/display-plugins/oculus/OculusBaseDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/oculus/OculusBaseDisplayPlugin.cpp @@ -14,6 +14,9 @@ using namespace Oculus; +OculusBaseDisplayPlugin::OculusBaseDisplayPlugin() : _ipd(OVR_DEFAULT_IPD) { +} + void OculusBaseDisplayPlugin::activate() { glm::uvec2 eyeSizes[2]; ovr_for_each_eye([&](ovrEyeType eye) { @@ -27,9 +30,12 @@ void OculusBaseDisplayPlugin::activate() { ovrMatrix4f_Projection(erd.Fov, 0.001f, 10.0f, ovrProjection_RightHanded); _compositeEyeProjections[eye] = toGlm(ovrPerspectiveProjection); - _eyeOffsets[eye] = erd.HmdToEyeViewOffset; + // We handle the eye offsets slightly differently, using an _ipd in the base class + // _eyeOffsets[eye] = erd.HmdToEyeViewOffset; + _eyeOffsets[eye] = { 0, 0, 0 }; eyeSizes[eye] = toGlm(ovrHmd_GetFovTextureSize(_hmd, eye, erd.Fov, 1.0f)); }); + _ipd = ovrHmd_GetFloat(_hmd, OVR_KEY_IPD, _ipd); _desiredFramebufferSize = uvec2( eyeSizes[0].x + eyeSizes[1].x, std::max(eyeSizes[0].y, eyeSizes[1].y)); diff --git a/libraries/display-plugins/src/display-plugins/oculus/OculusBaseDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/oculus/OculusBaseDisplayPlugin.h index e376ae12ba..401ee6579a 100644 --- a/libraries/display-plugins/src/display-plugins/oculus/OculusBaseDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/oculus/OculusBaseDisplayPlugin.h @@ -11,6 +11,7 @@ class OculusBaseDisplayPlugin : public MainWindowOpenGLDisplayPlugin { public: + OculusBaseDisplayPlugin(); // Stereo specific methods virtual bool isHmd() const override { return true; } virtual glm::mat4 getProjection(Eye eye, const glm::mat4& baseProjection) const override; @@ -22,5 +23,6 @@ public: virtual void resetSensors() override; virtual glm::mat4 getEyePose(Eye eye) const override; virtual glm::mat4 getHeadPose() const override; - +protected: + float _ipd; }; diff --git a/libraries/display-plugins/src/display-plugins/stereo/SideBySideStereoDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/stereo/SideBySideStereoDisplayPlugin.cpp index e348143250..72ef5249a8 100644 --- a/libraries/display-plugins/src/display-plugins/stereo/SideBySideStereoDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/stereo/SideBySideStereoDisplayPlugin.cpp @@ -17,7 +17,7 @@ #include -const QString SideBySideStereoDisplayPlugin::NAME("SBS Stereo Display"); +const QString SideBySideStereoDisplayPlugin::NAME("Debug Stereo Display"); const QString & SideBySideStereoDisplayPlugin::getName() const { return NAME; diff --git a/libraries/display-plugins/src/display-plugins/stereo/StereoDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/stereo/StereoDisplayPlugin.cpp index c741967328..3d5f73bfa8 100644 --- a/libraries/display-plugins/src/display-plugins/stereo/StereoDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/stereo/StereoDisplayPlugin.cpp @@ -52,6 +52,16 @@ glm::mat4 StereoDisplayPlugin::getModelview(Eye eye, const glm::mat4& baseModelv void StereoDisplayPlugin::activate() { WindowOpenGLDisplayPlugin::activate(); - CONTAINER->setFullscreen(qApp->primaryScreen()); + // FIXME there is a bug in the fullscreen setting, see + // Application::setFullscreen + //CONTAINER->setFullscreen(qApp->primaryScreen()); // FIXME Add menu items } + +glm::vec3 StereoDisplayPlugin::getEyeOffset(Eye eye) const { + glm::vec3 result(_ipd / 2.0f, 0, 0); + if (eye == Eye::Right) { + result *= -1.0f; + } + return result; +} diff --git a/libraries/display-plugins/src/display-plugins/stereo/StereoDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/stereo/StereoDisplayPlugin.h index bb1a4fd42c..77b1141aed 100644 --- a/libraries/display-plugins/src/display-plugins/stereo/StereoDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/stereo/StereoDisplayPlugin.h @@ -20,5 +20,8 @@ public: virtual glm::mat4 getProjection(Eye eye, const glm::mat4& baseProjection) const override; virtual glm::mat4 getModelview(Eye eye, const glm::mat4& baseModelview) const override; + virtual glm::vec3 getEyeOffset(Eye eye) const override; +protected: + float _ipd{ 0.064f }; }; diff --git a/libraries/gpu/src/gpu/Batch.cpp b/libraries/gpu/src/gpu/Batch.cpp index 3ecbc3b2f3..fb6618e953 100644 --- a/libraries/gpu/src/gpu/Batch.cpp +++ b/libraries/gpu/src/gpu/Batch.cpp @@ -288,3 +288,18 @@ void Batch::resetStages() { ADD_COMMAND(resetStages); } +void Batch::enableStereo(bool enable) { + _enableStereo = enable; +} + +bool Batch::isStereoEnabled() const { + return _enableStereo; +} + +void Batch::enableSkybox(bool enable) { + _enableSkybox = enable; +} + +bool Batch::isSkyboxEnabled() const { + return _enableSkybox; +} \ No newline at end of file diff --git a/libraries/gpu/src/gpu/Batch.h b/libraries/gpu/src/gpu/Batch.h index d48ffef209..ca74032c5e 100644 --- a/libraries/gpu/src/gpu/Batch.h +++ b/libraries/gpu/src/gpu/Batch.h @@ -26,7 +26,7 @@ ProfileRange(const char *name); ~ProfileRange(); }; - #define PROFILE_RANGE(name) ProfileRange profileRangeThis(name); +#define PROFILE_RANGE(name) ProfileRange profileRangeThis(name); #else #define PROFILE_RANGE(name) #endif @@ -47,6 +47,19 @@ public: ~Batch(); void clear(); + + // Batches may need to override the context level stereo settings + // if they're performing framebuffer copy operations, like the + // deferred lighting resolution mechanism + void enableStereo(bool enable = true); + bool isStereoEnabled() const; + + // Stereo batches will pre-translate the view matrix, but this isn't + // appropriate for skyboxes or other things intended to be drawn at + // infinite distance, so provide a mechanism to render in stereo + // without the pre-translation of the view. + void enableSkybox(bool enable = true); + bool isSkyboxEnabled() const; // Drawcalls void draw(Primitive primitiveType, uint32 numVertices, uint32 startVertex = 0); @@ -276,6 +289,9 @@ public: FramebufferCaches _framebuffers; QueryCaches _queries; + bool _enableStereo{ true }; + bool _enableSkybox{ false }; + protected: }; diff --git a/libraries/gpu/src/gpu/Context.cpp b/libraries/gpu/src/gpu/Context.cpp index 239c460c77..561a51b477 100644 --- a/libraries/gpu/src/gpu/Context.cpp +++ b/libraries/gpu/src/gpu/Context.cpp @@ -40,6 +40,18 @@ void Context::render(Batch& batch) { _backend->render(batch); } +void Context::enableStereo(bool enable) { + _backend->enableStereo(enable); +} + +void Context::setStereoProjections(const mat4 eyeProjections[2]) { + _backend->setStereoProjections(eyeProjections); +} + +void Context::setStereoViews(const mat4 eyeViews[2]) { + _backend->setStereoViews(eyeViews); +} + void Context::syncCache() { PROFILE_RANGE(__FUNCTION__); _backend->syncCache(); @@ -49,3 +61,26 @@ void Context::downloadFramebuffer(const FramebufferPointer& srcFramebuffer, cons _backend->downloadFramebuffer(srcFramebuffer, region, destImage); } +const Backend::TransformCamera& Backend::TransformCamera::recomputeDerived() const { + _projectionInverse = glm::inverse(_projection); + _viewInverse = glm::inverse(_view); + + Mat4 viewUntranslated = _view; + viewUntranslated[3] = Vec4(0.0f, 0.0f, 0.0f, 1.0f); + _projectionViewUntranslated = _projection * viewUntranslated; + return *this; +} + +Backend::TransformCamera Backend::TransformCamera::getEyeCamera(int eye, const StereoState& _stereo) const { + TransformCamera result = *this; + if (!_stereo._skybox) { + result._view = _stereo._eyeViews[eye] * result._view; + } else { + glm::mat4 skyboxView = _stereo._eyeViews[eye]; + skyboxView[3] = vec4(0, 0, 0, 1); + result._view = skyboxView * result._view; + } + result._projection = _stereo._eyeProjections[eye]; + result.recomputeDerived(); + return result; +} diff --git a/libraries/gpu/src/gpu/Context.h b/libraries/gpu/src/gpu/Context.h index 7158bd1a6d..9aca83e577 100644 --- a/libraries/gpu/src/gpu/Context.h +++ b/libraries/gpu/src/gpu/Context.h @@ -14,6 +14,8 @@ #include #include +#include + #include "Batch.h" #include "Resource.h" @@ -25,28 +27,58 @@ class QImage; namespace gpu { +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; + } + + 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]; + } + } + virtual void syncCache() = 0; virtual void downloadFramebuffer(const FramebufferPointer& srcFramebuffer, const Vec4i& region, QImage& destImage) = 0; + // UBO class... layout MUST match the layout in TransformCamera.slh class TransformObject { public: Mat4 _model; Mat4 _modelInverse; }; + // UBO class... layout MUST match the layout in TransformCamera.slh class TransformCamera { public: Mat4 _view; - Mat4 _viewInverse; - Mat4 _projectionViewUntranslated; + mutable Mat4 _viewInverse; + mutable Mat4 _projectionViewUntranslated; Mat4 _projection; - Mat4 _projectionInverse; + mutable Mat4 _projectionInverse; Vec4 _viewport; // Public value is int but float in the shader to stay in floats for all the transform computations. + + const Backend::TransformCamera& recomputeDerived() const; + TransformCamera getEyeCamera(int eye, const StereoState& stereo) const; }; template< typename T > @@ -113,7 +145,7 @@ public: } protected: - + StereoState _stereo; }; class Context { @@ -136,7 +168,9 @@ public: ~Context(); void render(Batch& batch); - + void enableStereo(bool enable = true); + void setStereoProjections(const mat4 eyeProjections[2]); + void setStereoViews(const mat4 eyeViews[2]); void syncCache(); // Downloading the Framebuffer is a synchronous action that is not efficient. diff --git a/libraries/gpu/src/gpu/Forward.h b/libraries/gpu/src/gpu/Forward.h new file mode 100644 index 0000000000..0fa315ef1c --- /dev/null +++ b/libraries/gpu/src/gpu/Forward.h @@ -0,0 +1,77 @@ +// +// Created by Bradley Austin Davis on 2015/08/15 +// Copyright 2015 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 +// +#pragma once +#ifndef hifi_gpu_Forward_h +#define hifi_gpu_Forward_h + +namespace gpu { + class Batch; + class Backend; + class Context; + typedef std::shared_ptr ContextPointer; + class GPUObject; + + typedef int Stamp; + typedef uint32_t uint32; + typedef int32_t int32; + typedef uint16_t uint16; + typedef int16_t int16; + typedef uint8_t uint8; + typedef int8_t int8; + + typedef uint8 Byte; + typedef uint32 Offset; + typedef std::vector Offsets; + + typedef glm::mat4 Mat4; + typedef glm::mat3 Mat3; + typedef glm::vec4 Vec4; + typedef glm::ivec4 Vec4i; + typedef glm::vec3 Vec3; + typedef glm::vec2 Vec2; + typedef glm::ivec2 Vec2i; + typedef glm::uvec2 Vec2u; + + class Element; + typedef Element Format; + class Swapchain; + typedef std::shared_ptr SwapchainPointer; + class Framebuffer; + typedef std::shared_ptr FramebufferPointer; + class Pipeline; + typedef std::shared_ptr PipelinePointer; + typedef std::vector Pipelines; + class Query; + typedef std::shared_ptr QueryPointer; + typedef std::vector Queries; + class Resource; + class Buffer; + typedef std::shared_ptr BufferPointer; + typedef std::vector Buffers; + class BufferView; + class Shader; + typedef Shader::Pointer ShaderPointer; + typedef std::vector Shaders; + class State; + typedef std::shared_ptr StatePointer; + typedef std::vector States; + class Stream; + class BufferStream; + typedef std::shared_ptr BufferStreamPointer; + class Texture; + class SphericalHarmonics; + typedef std::shared_ptr SHPointer; + class Sampler; + class Texture; + typedef std::shared_ptr TexturePointer; + typedef std::vector Textures; + class TextureView; + typedef std::vector TextureViews; +} + +#endif diff --git a/libraries/gpu/src/gpu/GLBackend.cpp b/libraries/gpu/src/gpu/GLBackend.cpp index 4afd2ba940..2270c0dce7 100644 --- a/libraries/gpu/src/gpu/GLBackend.cpp +++ b/libraries/gpu/src/gpu/GLBackend.cpp @@ -127,39 +127,29 @@ void GLBackend::renderPassTransfer(Batch& batch) { const Batch::Commands::value_type* command = batch.getCommands().data(); const Batch::CommandOffsets::value_type* offset = batch.getCommandOffsets().data(); - _transform._cameraTransforms.resize(0); - _transform._cameraTransforms.push_back(TransformCamera()); + // Reset the transform buffers + _transform._cameras.resize(0); _transform._cameraOffsets.clear(); - _transform._cameraOffsets.push_back(TransformStageState::Pair(0, 0)); - - _transform._objectTransforms.push_back(TransformObject()); - _transform._objectOffsets.push_back(TransformStageState::Pair(0, 0)); + _transform._objects.resize(0); _transform._objectOffsets.clear(); - _transform._objectTransforms.resize(0); - - _commandIndex = 0; - preUpdateTransform(); - int drawCount = 0; for (_commandIndex = 0; _commandIndex < numCommands; ++_commandIndex) { switch (*command) { case Batch::COMMAND_draw: case Batch::COMMAND_drawIndexed: case Batch::COMMAND_drawInstanced: case Batch::COMMAND_drawIndexedInstanced: - preUpdateTransform(); - ++drawCount; + _transform.preUpdate(_commandIndex, _stereo); break; case Batch::COMMAND_setModelTransform: case Batch::COMMAND_setViewportTransform: case Batch::COMMAND_setViewTransform: - case Batch::COMMAND_setProjectionTransform: - { + case Batch::COMMAND_setProjectionTransform: { CommandCall call = _commandCalls[(*command)]; (this->*(call))(batch, *offset); + break; } - break; default: break; @@ -167,44 +157,31 @@ void GLBackend::renderPassTransfer(Batch& batch) { command++; offset++; } - - - static QByteArray bufferData; - glBindBuffer(GL_UNIFORM_BUFFER, _transform._transformCameraBuffer); - bufferData.resize(_transform._cameraUboSize * _transform._cameraTransforms.size()); - for (size_t i = 0; i < _transform._cameraTransforms.size(); ++i) { - memcpy(bufferData.data() + (_transform._cameraUboSize * i), &_transform._cameraTransforms[i], sizeof(TransformCamera)); - } - glBufferData(GL_UNIFORM_BUFFER, bufferData.size(), bufferData.data(), GL_DYNAMIC_DRAW); - glBindBuffer(GL_UNIFORM_BUFFER, _transform._transformObjectBuffer); - bufferData.resize(_transform._objectUboSize * _transform._objectTransforms.size()); - for (size_t i = 0; i < _transform._objectTransforms.size(); ++i) { - memcpy(bufferData.data() + (_transform._objectUboSize * i), &_transform._objectTransforms[i], sizeof(TransformObject)); - } - glBufferData(GL_UNIFORM_BUFFER, bufferData.size(), bufferData.data(), GL_DYNAMIC_DRAW); - glBindBuffer(GL_UNIFORM_BUFFER, 0); - CHECK_GL_ERROR(); + _transform.transfer(); } void GLBackend::renderPassDraw(Batch& batch) { + _transform._objectsItr = _transform._objectOffsets.begin(); + _transform._camerasItr = _transform._cameraOffsets.begin(); const size_t numCommands = batch.getCommands().size(); const Batch::Commands::value_type* command = batch.getCommands().data(); const Batch::CommandOffsets::value_type* offset = batch.getCommandOffsets().data(); for (_commandIndex = 0; _commandIndex < numCommands; ++_commandIndex) { switch (*command) { // Ignore these commands on this pass, taken care of in the transfer pass + // Note we allow COMMAND_setViewportTransform to occur in both passes + // as it both updates the transform object (and thus the uniforms in the + // UBO) as well as executes the actual viewport call case Batch::COMMAND_setModelTransform: - case Batch::COMMAND_setViewportTransform: case Batch::COMMAND_setViewTransform: case Batch::COMMAND_setProjectionTransform: break; - default: - { + default: { CommandCall call = _commandCalls[(*command)]; (this->*(call))(batch, *offset); + break; } - break; } command++; @@ -213,8 +190,33 @@ void GLBackend::renderPassDraw(Batch& batch) { } void GLBackend::render(Batch& batch) { - renderPassTransfer(batch); - renderPassDraw(batch); + _stereo._skybox = batch.isSkyboxEnabled(); + // Allow the batch to override the rendering stereo settings + // for things like full framebuffer copy operations (deferred lighting passes) + bool savedStereo = _stereo._enable; + if (!batch.isStereoEnabled()) { + _stereo._enable = false; + } + + { + PROFILE_RANGE("Transfer"); + renderPassTransfer(batch); + } + + { + PROFILE_RANGE(_stereo._enable ? "LeftRender" : "Render"); + renderPassDraw(batch); + } + + if (_stereo._enable) { + PROFILE_RANGE("RightRender"); + _stereo._pass = 1; + renderPassDraw(batch); + _stereo._pass = 0; + } + + // Restore the saved stereo state for the next batch + _stereo._enable = savedStereo; } bool GLBackend::checkGLError(const char* name) { diff --git a/libraries/gpu/src/gpu/GLBackend.h b/libraries/gpu/src/gpu/GLBackend.h index 455240deb8..c97ea4e615 100644 --- a/libraries/gpu/src/gpu/GLBackend.h +++ b/libraries/gpu/src/gpu/GLBackend.h @@ -310,19 +310,22 @@ protected: void killTransform(); // Synchronize the state cache of this Backend with the actual real state of the GL Context void syncTransformStateCache(); - void updateTransform(); - void preUpdateTransform(); + void updateTransform() const; void resetTransformStage(); - struct TransformStageState { - TransformObject _transformObject; - TransformCamera _transformCamera; - std::vector _objectTransforms; - std::vector _cameraTransforms; + struct TransformStageState { + using TransformObjects = std::vector; + using TransformCameras = std::vector; + + TransformObject _object; + TransformCamera _camera; + TransformObjects _objects; + TransformCameras _cameras; + size_t _cameraUboSize{ 0 }; size_t _objectUboSize{ 0 }; - GLuint _transformObjectBuffer{ 0 }; - GLuint _transformCameraBuffer{ 0 }; + GLuint _objectBuffer{ 0 }; + GLuint _cameraBuffer{ 0 }; Transform _model; Transform _view; Mat4 _projection; @@ -336,6 +339,12 @@ protected: using List = std::list; List _cameraOffsets; List _objectOffsets; + mutable List::const_iterator _objectsItr; + mutable List::const_iterator _camerasItr; + + void preUpdate(size_t commandIndex, const StereoState& stereo); + void update(size_t commandIndex, const StereoState& stereo) const; + void transfer() const; } _transform; int32_t _uboAlignment{ 0 }; diff --git a/libraries/gpu/src/gpu/GLBackendOutput.cpp b/libraries/gpu/src/gpu/GLBackendOutput.cpp index d75d0cf521..33ae1dd0a3 100755 --- a/libraries/gpu/src/gpu/GLBackendOutput.cpp +++ b/libraries/gpu/src/gpu/GLBackendOutput.cpp @@ -198,6 +198,9 @@ void GLBackend::do_setFramebuffer(Batch& batch, uint32 paramOffset) { } void GLBackend::do_clearFramebuffer(Batch& batch, uint32 paramOffset) { + if (_stereo._enable && !_pipeline._stateCache.scissorEnable) { + qWarning("Clear without scissor in stereo mode"); + } uint32 masks = batch._params[paramOffset + 7]._uint; Vec4 color; diff --git a/libraries/gpu/src/gpu/GLBackendState.cpp b/libraries/gpu/src/gpu/GLBackendState.cpp index c5cc987fd1..9fdcbc0870 100644 --- a/libraries/gpu/src/gpu/GLBackendState.cpp +++ b/libraries/gpu/src/gpu/GLBackendState.cpp @@ -768,6 +768,12 @@ void GLBackend::do_setStateScissorRect(Batch& batch, uint32 paramOffset) { Vec4i rect; memcpy(&rect, batch.editData(batch._params[paramOffset]._uint), sizeof(Vec4i)); + if (_stereo._enable) { + rect.z /= 2; + if (_stereo._pass) { + rect.x += rect.z; + } + } glScissor(rect.x, rect.y, rect.z, rect.w); (void) CHECK_GL_ERROR(); } diff --git a/libraries/gpu/src/gpu/GLBackendTransform.cpp b/libraries/gpu/src/gpu/GLBackendTransform.cpp index 23b3dba14e..e33a8f8cde 100755 --- a/libraries/gpu/src/gpu/GLBackendTransform.cpp +++ b/libraries/gpu/src/gpu/GLBackendTransform.cpp @@ -33,16 +33,26 @@ void GLBackend::do_setProjectionTransform(Batch& batch, uint32 paramOffset) { void GLBackend::do_setViewportTransform(Batch& batch, uint32 paramOffset) { memcpy(&_transform._viewport, batch.editData(batch._params[paramOffset]._uint), sizeof(Vec4i)); + ivec4& vp = _transform._viewport; + // Where we assign the GL viewport - glViewport(_transform._viewport.x, _transform._viewport.y, _transform._viewport.z, _transform._viewport.w); + if (_stereo._enable) { + vp.z /= 2; + if (_stereo._pass) { + vp.x += vp.z; + } + int i = 0; + } + + glViewport(vp.x, vp.y, vp.z, vp.w); // The Viewport is tagged invalid because the CameraTransformUBO is not up to date and willl need update on next drawcall _transform._invalidViewport = true; } void GLBackend::initTransform() { - glGenBuffers(1, &_transform._transformObjectBuffer); - glGenBuffers(1, &_transform._transformCameraBuffer); + glGenBuffers(1, &_transform._objectBuffer); + glGenBuffers(1, &_transform._cameraBuffer); size_t cameraSize = sizeof(TransformCamera); while (_transform._cameraUboSize < cameraSize) { _transform._cameraUboSize += _uboAlignment; @@ -54,8 +64,8 @@ void GLBackend::initTransform() { } void GLBackend::killTransform() { - glDeleteBuffers(1, &_transform._transformObjectBuffer); - glDeleteBuffers(1, &_transform._transformCameraBuffer); + glDeleteBuffers(1, &_transform._objectBuffer); + glDeleteBuffers(1, &_transform._cameraBuffer); } void GLBackend::syncTransformStateCache() { @@ -72,73 +82,98 @@ void GLBackend::syncTransformStateCache() { _transform._model.setIdentity(); } -void GLBackend::preUpdateTransform() { +void GLBackend::TransformStageState::preUpdate(size_t commandIndex, const StereoState& stereo) { // Check all the dirty flags and update the state accordingly - if (_transform._invalidViewport) { - _transform._transformCamera._viewport = glm::vec4(_transform._viewport); + if (_invalidViewport) { + _camera._viewport = glm::vec4(_viewport); } - if (_transform._invalidProj) { - _transform._transformCamera._projection = _transform._projection; - _transform._transformCamera._projectionInverse = glm::inverse(_transform._projection); + if (_invalidProj) { + _camera._projection = _projection; } - if (_transform._invalidView) { - _transform._view.getInverseMatrix(_transform._transformCamera._view); - _transform._view.getMatrix(_transform._transformCamera._viewInverse); + if (_invalidView) { + _view.getInverseMatrix(_camera._view); } - if (_transform._invalidModel) { - _transform._model.getMatrix(_transform._transformObject._model); - _transform._model.getInverseMatrix(_transform._transformObject._modelInverse); + if (_invalidModel) { + _model.getMatrix(_object._model); + _model.getInverseMatrix(_object._modelInverse); } - if (_transform._invalidView || _transform._invalidProj) { - Mat4 viewUntranslated = _transform._transformCamera._view; - viewUntranslated[3] = Vec4(0.0f, 0.0f, 0.0f, 1.0f); - _transform._transformCamera._projectionViewUntranslated = _transform._transformCamera._projection * viewUntranslated; + if (_invalidView || _invalidProj || _invalidViewport) { + size_t offset = _cameraUboSize * _cameras.size(); + if (stereo._enable) { + _cameraOffsets.push_back(TransformStageState::Pair(commandIndex, offset)); + for (int i = 0; i < 2; ++i) { + _cameras.push_back(_camera.getEyeCamera(i, stereo)); + } + } else { + _cameraOffsets.push_back(TransformStageState::Pair(commandIndex, offset)); + _cameras.push_back(_camera.recomputeDerived()); + } } - if (_transform._invalidView || _transform._invalidProj || _transform._invalidViewport) { - _transform._cameraOffsets.push_back(TransformStageState::Pair(_commandIndex, _transform._cameraUboSize * _transform._cameraTransforms.size())); - _transform._cameraTransforms.push_back(_transform._transformCamera); - } - - if (_transform._invalidModel) { - _transform._objectOffsets.push_back(TransformStageState::Pair(_commandIndex, _transform._objectUboSize * _transform._objectTransforms.size())); - _transform._objectTransforms.push_back(_transform._transformObject); + if (_invalidModel) { + size_t offset = _objectUboSize * _objects.size(); + _objectOffsets.push_back(TransformStageState::Pair(commandIndex, offset)); + _objects.push_back(_object); } // Flags are clean - _transform._invalidView = _transform._invalidProj = _transform._invalidModel = _transform._invalidViewport = false; + _invalidView = _invalidProj = _invalidModel = _invalidViewport = false; } -void GLBackend::updateTransform() { +void GLBackend::TransformStageState::transfer() const { + static QByteArray bufferData; + glBindBuffer(GL_UNIFORM_BUFFER, _cameraBuffer); + bufferData.resize(_cameraUboSize * _cameras.size()); + for (size_t i = 0; i < _cameras.size(); ++i) { + memcpy(bufferData.data() + (_cameraUboSize * i), &_cameras[i], sizeof(TransformCamera)); + } + glBufferData(GL_UNIFORM_BUFFER, bufferData.size(), bufferData.data(), GL_DYNAMIC_DRAW); + glBindBuffer(GL_UNIFORM_BUFFER, _objectBuffer); + bufferData.resize(_objectUboSize * _objects.size()); + for (size_t i = 0; i < _objects.size(); ++i) { + memcpy(bufferData.data() + (_objectUboSize * i), &_objects[i], sizeof(TransformObject)); + } + glBufferData(GL_UNIFORM_BUFFER, bufferData.size(), bufferData.data(), GL_DYNAMIC_DRAW); + glBindBuffer(GL_UNIFORM_BUFFER, 0); + CHECK_GL_ERROR(); +} + +void GLBackend::TransformStageState::update(size_t commandIndex, const StereoState& stereo) const { int offset = -1; - while (!_transform._objectOffsets.empty() && _commandIndex >= _transform._objectOffsets.front().first) { - offset = _transform._objectOffsets.front().second; - _transform._objectOffsets.pop_front(); + while ((_objectsItr != _objectOffsets.end()) && (commandIndex >= (*_objectsItr).first)) { + offset = (*_objectsItr).second; + ++_objectsItr; } if (offset >= 0) { - glBindBufferRange(GL_UNIFORM_BUFFER, TRANSFORM_OBJECT_SLOT, - _transform._transformObjectBuffer, - offset, sizeof(Backend::TransformObject)); + glBindBufferRange(GL_UNIFORM_BUFFER, TRANSFORM_OBJECT_SLOT, + _objectBuffer, offset, sizeof(Backend::TransformObject)); } offset = -1; - while (!_transform._cameraOffsets.empty() && _commandIndex >= _transform._cameraOffsets.front().first) { - offset = _transform._cameraOffsets.front().second; - _transform._cameraOffsets.pop_front(); + while ((_camerasItr != _cameraOffsets.end()) && (commandIndex >= (*_camerasItr).first)) { + offset = (*_camerasItr).second; + ++_camerasItr; } if (offset >= 0) { - glBindBufferRange(GL_UNIFORM_BUFFER, TRANSFORM_CAMERA_SLOT, - _transform._transformCameraBuffer, - offset, sizeof(Backend::TransformCamera)); + // We include both camera offsets for stereo + if (stereo._enable && stereo._pass) { + offset += _cameraUboSize; + } + glBindBufferRange(GL_UNIFORM_BUFFER, TRANSFORM_CAMERA_SLOT, + _cameraBuffer, offset, sizeof(Backend::TransformCamera)); } (void)CHECK_GL_ERROR(); } +void GLBackend::updateTransform() const { + _transform.update(_commandIndex, _stereo); +} + void GLBackend::resetTransformStage() { } diff --git a/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp b/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp index fc53670fd0..e76983cce9 100644 --- a/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp +++ b/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp @@ -189,7 +189,6 @@ void ViveControllerManager::updateRendering(RenderArgs* args, render::ScenePoint renderHand(rightHand, batch, RIGHT_HAND); } - args->_context->syncCache(); args->_context->render(batch); } } diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index 5f0afd37d1..ecf7c34dfe 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -246,6 +246,5 @@ void AmbientOcclusion::run(const render::SceneContextPointer& sceneContext, cons DependencyManager::get()->renderQuad(batch, bottomLeft, topRight, texCoordTopLeft, texCoordBottomRight, color); // Ready to render - args->_context->syncCache(); args->_context->render((batch)); } diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index 6776fa6c79..a785a5d2ec 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -225,6 +225,7 @@ void DeferredLightingEffect::addSpotLight(const glm::vec3& position, float radiu void DeferredLightingEffect::prepare(RenderArgs* args) { gpu::Batch batch; + batch.enableStereo(false); batch.setStateScissorRect(args->_viewport); @@ -244,6 +245,9 @@ gpu::FramebufferPointer _copyFBO; void DeferredLightingEffect::render(RenderArgs* args) { gpu::Batch batch; + // Framebuffer copy operations cannot function as multipass stereo operations. + batch.enableStereo(false); + // perform deferred lighting, rendering to free fbo auto framebufferCache = DependencyManager::get(); @@ -555,6 +559,7 @@ void DeferredLightingEffect::render(RenderArgs* args) { void DeferredLightingEffect::copyBack(RenderArgs* args) { gpu::Batch batch; + batch.enableStereo(false); auto framebufferCache = DependencyManager::get(); QSize framebufferSize = framebufferCache->getFrameBufferSize(); diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index efef423623..ca3f87f53f 100755 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -35,6 +35,7 @@ void SetupDeferred::run(const SceneContextPointer& sceneContext, const RenderCon auto primaryFbo = DependencyManager::get()->getPrimaryFramebufferDepthColor(); gpu::Batch batch; + batch.enableStereo(false); batch.setFramebuffer(nullptr); batch.setFramebuffer(primaryFbo); @@ -159,6 +160,8 @@ void DrawOpaqueDeferred::run(const SceneContextPointer& sceneContext, const Rend RenderArgs* args = renderContext->args; gpu::Batch batch; + batch.setViewportTransform(args->_viewport); + batch.setStateScissorRect(args->_viewport); args->_batch = &batch; renderContext->_numDrawnOpaqueItems = inItems.size(); @@ -188,6 +191,8 @@ void DrawTransparentDeferred::run(const SceneContextPointer& sceneContext, const RenderArgs* args = renderContext->args; gpu::Batch batch; + batch.setViewportTransform(args->_viewport); + batch.setStateScissorRect(args->_viewport); args->_batch = &batch; renderContext->_numDrawnTransparentItems = inItems.size(); @@ -247,30 +252,42 @@ void DrawOverlay3D::run(const SceneContextPointer& sceneContext, const RenderCon renderContext->_numFeedOverlay3DItems = inItems.size(); renderContext->_numDrawnOverlay3DItems = inItems.size(); - RenderArgs* args = renderContext->args; - gpu::Batch batch; - args->_batch = &batch; - args->_whiteTexture = DependencyManager::get()->getWhiteTexture(); - - glm::mat4 projMat; - Transform viewMat; - args->_viewFrustum->evalProjectionMatrix(projMat); - args->_viewFrustum->evalViewTransform(viewMat); - - batch.setProjectionTransform(projMat); - batch.setViewTransform(viewMat); - batch.setViewportTransform(args->_viewport); - batch.setStateScissorRect(args->_viewport); - - batch.setPipeline(getOpaquePipeline()); - batch.setResourceTexture(0, args->_whiteTexture); - if (!inItems.empty()) { - batch.clearFramebuffer(gpu::Framebuffer::BUFFER_DEPTH, glm::vec4(), 1.f, 0, true); - renderItems(sceneContext, renderContext, inItems, renderContext->_maxDrawnOverlay3DItems); - } + RenderArgs* args = renderContext->args; - args->_context->render((*args->_batch)); - args->_batch = nullptr; - args->_whiteTexture.reset(); + // Clear the framebuffer without stereo + // Needs to be distinct from the other batch because using the clear call + // while stereo is enabled triggers a warning + { + gpu::Batch batch; + batch.enableStereo(false); + batch.clearFramebuffer(gpu::Framebuffer::BUFFER_DEPTH, glm::vec4(), 1.f, 0, true); + args->_context->render(batch); + } + + // Render the items + { + gpu::Batch batch; + args->_batch = &batch; + args->_whiteTexture = DependencyManager::get()->getWhiteTexture(); + + glm::mat4 projMat; + Transform viewMat; + args->_viewFrustum->evalProjectionMatrix(projMat); + args->_viewFrustum->evalViewTransform(viewMat); + + batch.setProjectionTransform(projMat); + batch.setViewTransform(viewMat); + batch.setViewportTransform(args->_viewport); + batch.setStateScissorRect(args->_viewport); + + batch.setPipeline(getOpaquePipeline()); + batch.setResourceTexture(0, args->_whiteTexture); + renderItems(sceneContext, renderContext, inItems, renderContext->_maxDrawnOverlay3DItems); + + args->_context->render((*args->_batch)); + args->_batch = nullptr; + args->_whiteTexture.reset(); + } + } } diff --git a/libraries/render/src/render/DrawStatus.cpp b/libraries/render/src/render/DrawStatus.cpp index 0c1b92b559..28b4344bf1 100644 --- a/libraries/render/src/render/DrawStatus.cpp +++ b/libraries/render/src/render/DrawStatus.cpp @@ -161,8 +161,5 @@ void DrawStatus::run(const SceneContextPointer& sceneContext, const RenderContex batch.draw(gpu::TRIANGLES, 24, 0); } - // Before rendering the batch make sure we re in sync with gl state - args->_context->syncCache(); - renderContext->args->_context->syncCache(); - args->_context->render((batch)); + args->_context->render(batch); } diff --git a/libraries/render/src/render/DrawTask.cpp b/libraries/render/src/render/DrawTask.cpp index ff2cf6ff41..0754d81bde 100755 --- a/libraries/render/src/render/DrawTask.cpp +++ b/libraries/render/src/render/DrawTask.cpp @@ -258,6 +258,9 @@ void DrawBackground::run(const SceneContextPointer& sceneContext, const RenderCo } RenderArgs* args = renderContext->args; gpu::Batch batch; + batch.enableSkybox(true); + batch.setViewportTransform(args->_viewport); + batch.setStateScissorRect(args->_viewport); args->_batch = &batch; glm::mat4 projMat; @@ -271,9 +274,6 @@ void DrawBackground::run(const SceneContextPointer& sceneContext, const RenderCo renderItems(sceneContext, renderContext, inItems); args->_context->render((*args->_batch)); args->_batch = nullptr; - - // Force the context sync - args->_context->syncCache(); } void ItemMaterialBucketMap::insert(const ItemID& id, const model::MaterialKey& key) {