From 1b7efe9a02544d49cafb5eda73a679e2366c34db Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Fri, 5 Jun 2015 00:00:57 -0700
Subject: [PATCH] Working on display plugins

---
 interface/src/Application.cpp                 |  59 +++--
 interface/src/Application.h                   |  13 +-
 interface/src/MainWindow.cpp                  |   3 +
 interface/src/Menu.cpp                        |   4 +
 interface/src/Menu.h                          |   2 -
 .../src/ui/ApplicationOverlayCompositor.cpp   | 209 ++++++++++++++++++
 .../src/ui/ApplicationOverlayCompositor.h     |  37 ++++
 .../src/display-plugins/DisplayPlugin.h       |   9 +-
 .../MainWindowOpenGLDisplayPlugin.cpp         |  43 ++--
 .../MainWindowOpenGLDisplayPlugin.h           |  11 +-
 .../src/display-plugins/NullDisplayPlugin.cpp |   3 +-
 .../src/display-plugins/NullDisplayPlugin.h   |   3 +-
 .../src/display-plugins/OglplusHelpers.h      |  29 +--
 .../display-plugins/OpenGLDisplayPlugin.cpp   |  31 +--
 .../src/display-plugins/OpenGLDisplayPlugin.h |  12 +-
 .../WidgetOpenGLDisplayPlugin.cpp             |   5 +-
 .../WindowOpenGLDisplayPlugin.cpp             |  12 +-
 .../WindowOpenGLDisplayPlugin.h               |   6 +-
 .../oculus/OculusWin32DisplayPlugin.cpp       | 109 ++++-----
 .../oculus/OculusWin32DisplayPlugin.h         |   4 +-
 .../stereo/InterleavedStereoDisplayPlugin.cpp |   5 -
 .../stereo/InterleavedStereoDisplayPlugin.h   |   3 -
 .../stereo/SideBySideStereoDisplayPlugin.cpp  |  80 -------
 .../stereo/SideBySideStereoDisplayPlugin.h    |   3 -
 .../plugins/src/plugins/PluginContainer.h     |   4 +-
 25 files changed, 430 insertions(+), 269 deletions(-)
 create mode 100644 interface/src/ui/ApplicationOverlayCompositor.cpp
 create mode 100644 interface/src/ui/ApplicationOverlayCompositor.h

diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp
index 44d5b880f3..0dff8af5c9 100644
--- a/interface/src/Application.cpp
+++ b/interface/src/Application.cpp
@@ -90,6 +90,7 @@
 #include <UserActivityLogger.h>
 #include <UUID.h>
 #include <VrMenu.h>
+#include <ui/ApplicationOverlayCompositor.h>
 
 #include "Application.h"
 #include "AudioClient.h"
@@ -101,6 +102,7 @@
 #include "Util.h"
 #include "InterfaceLogging.h"
 
+#include "GlWindow.h"
 #include "avatar/AvatarManager.h"
 
 #include "audio/AudioToolBox.h"
@@ -506,29 +508,39 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
     
     ResourceCache::setRequestLimit(3);
 
-    _window->setCentralWidget(new QWidget());
+    _offscreenContext->create();
+    _offscreenContext->makeCurrent();
 
+    _glWindow = new GlWindow(_offscreenContext->getContext());
+
+    QWidget* container = QWidget::createWindowContainer(_glWindow);
+    container->setFocusPolicy(Qt::StrongFocus);
+    _window->setCentralWidget(container);
     _window->restoreGeometry();
-
     _window->setVisible(true);
+    container->setFocus();
+    _offscreenContext->makeCurrent();
+    initializeGL();
+    // initialization continues in initializeGL when OpenGL context is ready
+
+
+    _menuBarHeight = Menu::getInstance()->height();
 
 #if 0
     _fullscreenMenuWidget->setParent(_glWidget);
-#endif
-
-    _menuBarHeight = Menu::getInstance()->height();
     if (Menu::getInstance()->isOptionChecked(MenuOption::Fullscreen)) {
         setFullscreen(true);  // Initialize menu bar show/hide
     }
+#endif
+
 
     _toolWindow = new ToolWindow();
     _toolWindow->setWindowFlags(_toolWindow->windowFlags() | Qt::WindowStaysOnTopHint);
     _toolWindow->setWindowTitle("Tools");
 
-    _offscreenContext->create();
+
+    _compositor = CompositorPtr(new ApplicationOverlayCompositor());
     _offscreenContext->makeCurrent();
-    initializeGL();
-    // initialization continues in initializeGL when OpenGL context is ready
 
     // Tell our entity edit sender about our known jurisdictions
     _entityEditSender.setServerJurisdictions(&_entityServerJurisdictions);
@@ -949,15 +961,16 @@ void Application::paintGL() {
     // has completed before we start trying to read from it in another context.  However
     // once we have multi-threaded rendering, this will almost certainly be critical,
     // but may be better handled with a fence object
-    glFinish();
-
-    
+    // glFinish();
     _offscreenContext->doneCurrent();
     Q_ASSERT(!QOpenGLContext::currentContext());
-    displayPlugin->preDisplay();
 
-    displayPlugin->display(gpu::GLBackend::getTextureID(finalFbo->getRenderBuffer(0)), finalFbo->getSize(),
-                           _applicationOverlay.getOverlayTexture(), getCanvasSize());
+    GLuint finalTexture = _compositor->composite(displayPlugin,
+        gpu::GLBackend::getTextureID(finalFbo->getRenderBuffer(0)), finalFbo->getSize(),
+        _applicationOverlay.getOverlayTexture(), getCanvasSize());
+
+    displayPlugin->preDisplay();
+    displayPlugin->display(finalTexture, finalFbo->getSize());
     displayPlugin->finishFrame();
     Q_ASSERT(!QOpenGLContext::currentContext());
     _offscreenContext->makeCurrent();
@@ -1427,7 +1440,7 @@ void Application::mouseMoveEvent(QMouseEvent* event, unsigned int deviceID) {
         return;
     }
     
-
+#if 0
     if (Menu::getInstance()->isOptionChecked(MenuOption::Fullscreen)) {
         // Show/hide menu bar in fullscreen
         if (event->globalY() > _menuBarHeight) {
@@ -1438,6 +1451,7 @@ void Application::mouseMoveEvent(QMouseEvent* event, unsigned int deviceID) {
             Menu::getInstance()->setFixedHeight(_menuBarHeight);
         }
     }
+#endif
 
     _entities.mouseMoveEvent(event, deviceID);
     
@@ -1764,6 +1778,7 @@ void Application::idle() {
     emit checkBackgroundDownloads();
 }
 
+#if 0
 void Application::setFullscreen(bool fullscreen) {
     if (Menu::getInstance()->isOptionChecked(MenuOption::Fullscreen) != fullscreen) {
         Menu::getInstance()->getActionForOption(MenuOption::Fullscreen)->setChecked(fullscreen);
@@ -1822,7 +1837,6 @@ void Application::setFullscreen(bool fullscreen) {
     }
 }
 
-#if 0
 void Application::setEnable3DTVMode(bool enable3DTVMode) {
     resizeGL();
 }
@@ -3006,8 +3020,11 @@ PickRay Application::computePickRay(float x, float y) const {
     if (isHMDMode()) {
         getApplicationOverlay().computeHmdPickRay(glm::vec2(x, y), result.origin, result.direction);
     } else {
-        auto frustum = activeRenderingThread ? getDisplayViewFrustum() : getViewFrustum();
-        frustum->computePickRay(x, y, result.origin, result.direction);
+        if (QThread::currentThread() == activeRenderingThread) {
+            getDisplayViewFrustum()->computePickRay(x, y, result.origin, result.direction);
+        } else {
+            getViewFrustum()->computePickRay(x, y, result.origin, result.direction);
+        }
     }
     return result;
 }
@@ -3214,7 +3231,7 @@ void Application::displaySide(const Camera& theCamera, bool selfAvatarOnly) {
         skybox = skyStage->getSkybox();
         if (skybox) {
             gpu::Batch batch;
-            model::Skybox::render(batch, _viewFrustum, *skybox);
+            model::Skybox::render(batch, _displayViewFrustum, *skybox);
 
             gpu::GLBackend::renderBatch(batch);
             glUseProgram(0);
@@ -4656,6 +4673,6 @@ void Application::addMenuItem(const QString& path, std::function<void()> onClick
 
 }
 
-QMainWindow* Application::getAppMainWindow() {
-    return _window;
+GlWindow* Application::getVisibleWindow() {
+    return _glWindow;
 }
diff --git a/interface/src/Application.h b/interface/src/Application.h
index db407fc443..a6bb507890 100644
--- a/interface/src/Application.h
+++ b/interface/src/Application.h
@@ -48,7 +48,6 @@
 #include "DatagramProcessor.h"
 #include "Environment.h"
 #include "FileLogger.h"
-#include "GLCanvas.h"
 #include "Menu.h"
 #include "PacketHeaders.h"
 #include "Physics.h"
@@ -91,6 +90,9 @@ class MainWindow;
 class Node;
 class ProgramObject;
 class ScriptEngine;
+class GlWindow;
+class ApplicationOverlayCompositor;
+using CompositorPtr = std::shared_ptr<ApplicationOverlayCompositor>;
 
 static const float NODE_ADDED_RED   = 0.0f;
 static const float NODE_ADDED_GREEN = 1.0f;
@@ -137,6 +139,7 @@ class Application;
 
 typedef bool (Application::* AcceptURLMethod)(const QString &);
 
+
 class Application : public QApplication, public AbstractViewStateInterface, AbstractScriptingServicesInterface, PluginContainer {
     Q_OBJECT
 
@@ -299,7 +302,7 @@ public:
 
     // Plugin container support
     virtual void addMenuItem(const QString& path, std::function<void()> onClicked, bool checkable, bool checked, const QString& groupName);
-    virtual QMainWindow* getAppMainWindow();
+    virtual GlWindow* getVisibleWindow();
 
     private:
     DisplayPlugin * getActiveDisplayPlugin();
@@ -446,8 +449,11 @@ private slots:
 
     void connectedToDomain(const QString& hostname);
 
+#if 0
     friend class HMDToolsDialog;
     void setFullscreen(bool fullscreen);
+#endif
+
     void cameraMenuChanged();
 
     void closeMirrorView();
@@ -544,6 +550,8 @@ private:
     ViewFrustum _shadowViewFrustum;
     quint64 _lastQueriedTime;
 
+    CompositorPtr _compositor;
+
     float _trailingAudioLoudness;
 
     OctreeQuery _octreeQuery; // NodeData derived class for querying octee cells from octree servers
@@ -653,6 +661,7 @@ private:
     QThread _settingsThread;
     QTimer _settingsTimer;
     
+    GlWindow* _glWindow{ nullptr };
     void checkSkeleton();
 
     QWidget* _fullscreenMenuWidget = new QWidget();
diff --git a/interface/src/MainWindow.cpp b/interface/src/MainWindow.cpp
index e30de96890..a70fdd8a12 100644
--- a/interface/src/MainWindow.cpp
+++ b/interface/src/MainWindow.cpp
@@ -98,9 +98,12 @@ void MainWindow::changeEvent(QEvent* event) {
             emit windowShown(true);
         }
 
+#if 0
         if (isFullScreen() != Menu::getInstance()->isOptionChecked(MenuOption::Fullscreen)) {
             Menu::getInstance()->setIsOptionChecked(MenuOption::Fullscreen, isFullScreen());
         }
+#endif
+
     } else if (event->type() == QEvent::ActivationChange) {
         if (isActiveWindow()) {
             emit windowShown(true);
diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp
index a842bc777d..be17250420 100644
--- a/interface/src/Menu.cpp
+++ b/interface/src/Menu.cpp
@@ -239,6 +239,7 @@ Menu::Menu() {
         displayModeGroup->setExclusive(true);
     }
 
+#if 0
     addCheckableActionToQMenuAndActionHash(viewMenu,
                                            MenuOption::Fullscreen,
 #ifdef Q_OS_MAC
@@ -249,6 +250,7 @@ Menu::Menu() {
                                            false,
                                            qApp,
                                            SLOT(setFullscreen(bool)));
+#endif
 
     addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::FirstPerson,
         0, // QML Qt::Key_P,
@@ -260,6 +262,7 @@ Menu::Menu() {
         0, // QML Qt::Key_H,
         false, qApp, SLOT(cameraMenuChanged()));
 
+#if 0
     addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::HMDTools,
 #ifdef Q_OS_MAC
                                            Qt::META | Qt::Key_H,
@@ -269,6 +272,7 @@ Menu::Menu() {
                                            false,
                                            dialogsManager.data(),
                                            SLOT(hmdTools(bool)));
+#endif
 
     addActionToQMenuAndActionHash(editMenu, MenuOption::Attachments, 0,
         dialogsManager.data(), SLOT(editAttachments()));
diff --git a/interface/src/Menu.h b/interface/src/Menu.h
index e7888be3b7..a20759315c 100644
--- a/interface/src/Menu.h
+++ b/interface/src/Menu.h
@@ -194,12 +194,10 @@ namespace MenuOption {
     const QString FilterSixense = "Smooth Sixense Movement";
     const QString FirstPerson = "First Person";
     const QString FrameTimer = "Show Timer";
-    const QString Fullscreen = "Fullscreen";
     const QString FullscreenMirror = "Fullscreen Mirror";
     const QString GlowWhenSpeaking = "Glow When Speaking";
     const QString NamesAboveHeads = "Names Above Heads";
     const QString GoToUser = "Go To User";
-    const QString HMDTools = "HMD Tools";
     const QString IncreaseAvatarSize = "Increase Avatar Size";
     const QString KeyboardMotorControl = "Enable Keyboard Motor Control";
     const QString LeapMotionOnHMD = "Leap Motion on HMD";
diff --git a/interface/src/ui/ApplicationOverlayCompositor.cpp b/interface/src/ui/ApplicationOverlayCompositor.cpp
new file mode 100644
index 0000000000..d3fb32936d
--- /dev/null
+++ b/interface/src/ui/ApplicationOverlayCompositor.cpp
@@ -0,0 +1,209 @@
+#include "ApplicationOverlayCompositor.h"
+
+#include <TextureCache.h>
+#include <PathUtils.h>
+#include <ViewFrustum.h>
+#include <MatrixStack.h>
+#include <gpu/GLBackend.h>
+
+#define DEFAULT_HMD_UI_ANGULAR_SIZE 72.0f
+
+ApplicationOverlayCompositor::ApplicationOverlayCompositor() {
+    using namespace oglplus;
+
+    auto currentContext = QOpenGLContext::currentContext();
+    Q_ASSERT(currentContext);
+    _canvas.create(currentContext);
+    _canvas.makeCurrent();
+    Q_ASSERT(0 == glGetError());
+    currentContext = QOpenGLContext::currentContext();
+    Q_ASSERT(currentContext);
+
+    Context::ClearColor(0, 0, 0, 1);
+    Q_ASSERT(0 == glGetError());
+    Context::BlendFunc(BlendFunction::SrcAlpha, BlendFunction::OneMinusSrcAlpha);
+    Q_ASSERT(0 == glGetError());
+    Context::Disable(Capability::Blend);
+    Q_ASSERT(0 == glGetError());
+    Context::Disable(Capability::DepthTest);
+    Q_ASSERT(0 == glGetError());
+    Context::Disable(Capability::CullFace);
+    Q_ASSERT(0 == glGetError());
+
+    _program = loadDefaultShader();
+    _plane = loadPlane(_program);
+
+    _program = loadDefaultShader();
+    _plane = loadPlane(_program);
+    _hmdUiSurface = loadSphereSection(_program, glm::radians(DEFAULT_HMD_UI_ANGULAR_SIZE));
+
+    _crosshairTexture = DependencyManager::get<TextureCache>()->
+        getImageTexture(PathUtils::resourcesPath() + "images/sixense-reticle.png");
+}
+
+
+GLuint ApplicationOverlayCompositor::composite(DisplayPlugin* plugin,
+        GLuint sceneTexture, const glm::uvec2& sceneSize,
+        GLuint overlayTexture, const glm::uvec2& overlaySize) {
+    using namespace oglplus;
+    _canvas.makeCurrent();
+    if (!_fbo || sceneSize != _fbo->size) {
+        _fbo = BasicFramebufferWrapperPtr(new BasicFramebufferWrapper());
+        _fbo->Init(sceneSize);
+    }
+    _fbo->Bound(Framebuffer::Target::Draw, [&] {
+        Context::Clear().ColorBuffer();
+        if (plugin->isHmd()) {
+            compositeHmd(plugin, sceneTexture, sceneSize, overlayTexture, overlaySize);
+        } else if (plugin->isStereo()) {
+            compositeStereo(plugin, sceneTexture, sceneSize, overlayTexture, overlaySize);
+        } else {
+            composite2D(plugin, sceneTexture, sceneSize, overlayTexture, overlaySize);
+        }
+    });
+    GLuint result = GetName(_fbo->color);
+    _canvas.doneCurrent();
+    return result;
+}
+
+void ApplicationOverlayCompositor::composite2D(DisplayPlugin* plugin,
+    GLuint sceneTexture, const glm::uvec2& sceneSize,
+    GLuint overlayTexture, const glm::uvec2& overlaySize) {
+    using namespace oglplus;
+    const uvec2 size = toGlm(plugin->getDeviceSize());
+
+    Q_ASSERT(0 == glGetError());
+
+    Context::Viewport(size.x, size.y);
+    _program->Bind();
+    Mat4Uniform(*_program, "ModelView").Set(mat4());
+    Mat4Uniform(*_program, "Projection").Set(mat4());
+    glBindTexture(GL_TEXTURE_2D, sceneTexture);
+    _plane->Use();
+    _plane->Draw();
+    Context::Enable(Capability::Blend);
+    glBindTexture(GL_TEXTURE_2D, overlayTexture);
+    _plane->Draw();
+    Context::Disable(Capability::Blend);
+    glBindTexture(GL_TEXTURE_2D, 0);
+
+    // FIXME add the cursor
+
+    Q_ASSERT(0 == glGetError());
+}
+
+
+template <typename F>
+void sbs_for_each_eye(const uvec2& size, F f) {
+    QRect r(QPoint(0, 0), QSize(size.x / 2, size.y));
+    for_each_eye([&](Eye eye) {
+        oglplus::Context::Viewport(r.x(), r.y(), r.width(), r.height());
+        f(eye);
+    }, [&] {
+        r.moveLeft(r.width());
+    });
+}
+
+void ApplicationOverlayCompositor::compositeStereo(DisplayPlugin* plugin,
+    GLuint sceneTexture, const glm::uvec2& sceneSize,
+    GLuint overlayTexture, const glm::uvec2& overlaySize) {
+    using namespace oglplus;
+
+    Q_ASSERT(0 == glGetError());
+    const uvec2 size = sceneSize;
+
+    Context::Viewport(size.x, size.y);
+
+    _program->Bind();
+
+    Mat4Uniform(*_program, "ModelView").Set(mat4());
+    Mat4Uniform(*_program, "Projection").Set(mat4());
+
+    glBindTexture(GL_TEXTURE_2D, sceneTexture);
+
+    _plane->Use();
+    _plane->Draw();
+
+    // FIXME the 
+    const float screenAspect = aspect(size);
+    const GLfloat distance = 1.0f;
+    const GLfloat halfQuadHeight = distance * tan(DEFAULT_FIELD_OF_VIEW_DEGREES);
+    const GLfloat halfQuadWidth = halfQuadHeight * screenAspect;
+    const GLfloat quadWidth = halfQuadWidth * 2.0f;
+    const GLfloat quadHeight = halfQuadHeight * 2.0f;
+
+    vec3 quadSize(quadWidth, quadHeight, 1.0f);
+    quadSize = vec3(1.0f) / quadSize;
+
+    using namespace oglplus;
+    Context::Enable(Capability::Blend);
+    glBindTexture(GL_TEXTURE_2D, overlayTexture);
+
+    mat4 pr = glm::perspective(glm::radians(DEFAULT_FIELD_OF_VIEW_DEGREES), screenAspect, DEFAULT_NEAR_CLIP, DEFAULT_FAR_CLIP);
+    Mat4Uniform(*_program, "Projection").Set(pr);
+
+    // Position the camera relative to the overlay texture
+    MatrixStack mv;
+    mv.translate(vec3(0, 0, -distance)).scale(vec3(0.7f, 0.7f / screenAspect, 1.0f)); // .scale(vec3(quadWidth, quadHeight, 1.0));
+    sbs_for_each_eye(size, [&](Eye eye) {
+        mv.withPush([&] {
+            // translate 
+            mv.top() = plugin->getModelview(eye, mv.top());
+            Mat4Uniform(*_program, "ModelView").Set(mv.top());
+            _plane->Draw();
+        });
+    });
+
+    glBindTexture(GL_TEXTURE_2D, gpu::GLBackend::getTextureID(_crosshairTexture));
+    glm::vec2 canvasSize = plugin->getCanvasSize();
+    glm::vec2 mouse = vec2(0); // toGlm(_window->mapFromGlobal(QCursor::pos()));
+    mouse /= canvasSize;
+    mouse *= 2.0f;
+    mouse -= 1.0f;
+    mouse.y *= -1.0f;
+    sbs_for_each_eye(size, [&](Eye eye) {
+        mv.withPush([&] {
+            // translate 
+            mv.top() = plugin->getModelview(eye, mv.top());
+            mv.translate(mouse);
+            //mv.scale(0.05f);
+            mv.scale(vec3(0.025f, 0.05f, 1.0f));
+            Mat4Uniform(*_program, "ModelView").Set(mv.top());
+            _plane->Draw();
+        });
+    });
+    Context::Disable(Capability::Blend);
+
+}
+
+void ApplicationOverlayCompositor::compositeHmd(DisplayPlugin* plugin,
+    GLuint sceneTexture, const glm::uvec2& sceneSize,
+    GLuint overlayTexture, const glm::uvec2& overlaySize) {
+    using namespace oglplus;
+    auto size = sceneSize;
+
+    Context::Viewport(size.x, size.y);
+
+    glClearColor(0, 0, 0, 0);
+    Context::Clear().ColorBuffer();
+
+    _program->Bind();
+    Mat4Uniform(*_program, "Projection").Set(mat4());
+    Mat4Uniform(*_program, "ModelView").Set(mat4());
+    glBindTexture(GL_TEXTURE_2D, sceneTexture);
+    _plane->Use();
+    _plane->Draw();
+
+
+    Context::Enable(Capability::Blend);
+    glBindTexture(GL_TEXTURE_2D, overlayTexture);
+    for_each_eye([&](Eye eye) {
+        Context::Viewport(eye == Left ? 0 : size.x / 2, 0, size.x / 2, size.y);
+        glm::mat4 m = plugin->getProjection(eye, glm::mat4());
+        Mat4Uniform(*_program, "Projection").Set(m);
+        Mat4Uniform(*_program, "ModelView").Set(glm::scale(glm::inverse(plugin->getModelview(eye, mat4())), vec3(1)));
+        _hmdUiSurface->Use();
+        _hmdUiSurface->Draw();
+    });
+    Context::Disable(Capability::Blend);
+}
diff --git a/interface/src/ui/ApplicationOverlayCompositor.h b/interface/src/ui/ApplicationOverlayCompositor.h
new file mode 100644
index 0000000000..2110e4fd08
--- /dev/null
+++ b/interface/src/ui/ApplicationOverlayCompositor.h
@@ -0,0 +1,37 @@
+
+#pragma once
+
+#include <gpu/Texture.h>
+#include <display-plugins/DisplayPlugin.h>
+#include <display-plugins/OglplusHelpers.h>
+#include <OffscreenGlCanvas.h>
+
+class ApplicationOverlayCompositor {
+public:
+    ApplicationOverlayCompositor();
+    GLuint composite(DisplayPlugin* plugin,
+            GLuint sceneTexture, const glm::uvec2& sceneSize,
+            GLuint overlayTexture, const glm::uvec2& overlaySize);
+
+private:
+    OffscreenGlCanvas _canvas;
+    BasicFramebufferWrapperPtr _fbo;
+    ProgramPtr          _program;
+    ShapeWrapperPtr     _plane;
+    ShapeWrapperPtr     _hmdUiSurface;
+    gpu::TexturePointer _crosshairTexture;
+
+    void composite2D(DisplayPlugin* plugin,
+            GLuint sceneTexture, const glm::uvec2& sceneSize,
+            GLuint overlayTexture, const glm::uvec2& overlaySize);
+
+    void compositeStereo(DisplayPlugin* plugin,
+            GLuint sceneTexture, const glm::uvec2& sceneSize,
+            GLuint overlayTexture, const glm::uvec2& overlaySize);
+
+    void compositeHmd(DisplayPlugin* plugin,
+            GLuint sceneTexture, const glm::uvec2& sceneSize,
+            GLuint overlayTexture, const glm::uvec2& overlaySize);
+};
+
+using CompositorPtr = std::shared_ptr<ApplicationOverlayCompositor>;
diff --git a/libraries/display-plugins/src/display-plugins/DisplayPlugin.h b/libraries/display-plugins/src/display-plugins/DisplayPlugin.h
index e9a5d4a383..90526d7861 100644
--- a/libraries/display-plugins/src/display-plugins/DisplayPlugin.h
+++ b/libraries/display-plugins/src/display-plugins/DisplayPlugin.h
@@ -68,13 +68,12 @@ public:
      *  OpenGL context
      */
     virtual void preDisplay() = 0;
+
     /**
-     *  Sends the scene texture and the overlay texture to the display plugin.
-     *  The plugin is responsible for compositing these and adding rendering of
-     *  additional elements like mouse and hydra pointers as required
+     *  Sends the scene texture to the display plugin.
      */
-    virtual void display(GLuint sceneTexture, const glm::uvec2& sceneSize,
-                         GLuint overlayTexture, const glm::uvec2& overlaySize) = 0;
+    virtual void display(GLuint sceneTexture, const glm::uvec2& sceneSize) = 0;
+
     /**
      *  Called by the application immeidately after display.  For OpenGL based
      *  displays, this is the best place to put the buffer swap
diff --git a/libraries/display-plugins/src/display-plugins/MainWindowOpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/MainWindowOpenGLDisplayPlugin.cpp
index 9f909213d7..a7acfbea8b 100644
--- a/libraries/display-plugins/src/display-plugins/MainWindowOpenGLDisplayPlugin.cpp
+++ b/libraries/display-plugins/src/display-plugins/MainWindowOpenGLDisplayPlugin.cpp
@@ -7,32 +7,47 @@
 //
 #include "MainWindowOpenGLDisplayPlugin.h"
 
-#include <GlWindow.h>
 #include <QOpenGLContext>
-#include <plugins/PluginContainer.h>
 #include <QWidget>
 #include <QMainWindow>
 
+#include <GlWindow.h>
+#include <plugins/PluginContainer.h>
+
 MainWindowOpenGLDisplayPlugin::MainWindowOpenGLDisplayPlugin() {
 }
 
-void MainWindowOpenGLDisplayPlugin::activate(PluginContainer * container) {
-    WindowOpenGLDisplayPlugin::activate(container);
+GlWindow* MainWindowOpenGLDisplayPlugin::createWindow(PluginContainer * container) {
+    return container->getVisibleWindow();
 }
 
 void MainWindowOpenGLDisplayPlugin::customizeWindow(PluginContainer * container) {
-    // Can't set the central widget here, because it seems to mess up the context creation.
 }
 
-void MainWindowOpenGLDisplayPlugin::customizeContext(PluginContainer * container) {
-    WindowOpenGLDisplayPlugin::customizeContext(container);
-    QWidget* widget = QWidget::createWindowContainer(_window);
-    auto mainWindow = container->getAppMainWindow();
-    mainWindow->setCentralWidget(widget);
-    mainWindow->resize(mainWindow->geometry().size());
-    _window->resize(_window->geometry().size());
+void MainWindowOpenGLDisplayPlugin::destroyWindow() {
+    _window = nullptr;
 }
 
-void MainWindowOpenGLDisplayPlugin::deactivate() {
-    WindowOpenGLDisplayPlugin::deactivate();
+void MainWindowOpenGLDisplayPlugin::display(
+    GLuint finalTexture, const glm::uvec2& sceneSize) {
+    OpenGLDisplayPlugin::display(finalTexture, sceneSize);
+    return;
+
+    using namespace oglplus;
+    glClearColor(0, 1, 0, 1);
+    uvec2 size = toGlm(getDeviceSize());
+    Context::Viewport(size.x, size.y);
+    Context::Clear().ColorBuffer();
+    glEnable(GL_TEXTURE_2D);
+    glBindTexture(GL_TEXTURE_2D, finalTexture);
+    glBegin(GL_QUADS);
+        glTexCoord2f(0, 0);
+        glVertex2f(-1, -1);
+        glTexCoord2f(1, 0);
+        glVertex2f(1, -1);
+        glTexCoord2f(1, 1);
+        glVertex2f(1, 1);
+        glTexCoord2f(0, 1);
+        glVertex2f(-1, 1);
+    glEnd();
 }
diff --git a/libraries/display-plugins/src/display-plugins/MainWindowOpenGLDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/MainWindowOpenGLDisplayPlugin.h
index a93a6b8edd..81404acaa2 100644
--- a/libraries/display-plugins/src/display-plugins/MainWindowOpenGLDisplayPlugin.h
+++ b/libraries/display-plugins/src/display-plugins/MainWindowOpenGLDisplayPlugin.h
@@ -9,17 +9,16 @@
 
 #include "WindowOpenGLDisplayPlugin.h"
 
-class GlWindow;
-class QSurfaceFormat;
+class QGLWidget;
 
 class MainWindowOpenGLDisplayPlugin : public WindowOpenGLDisplayPlugin {
     Q_OBJECT
 public:
     MainWindowOpenGLDisplayPlugin();
-    virtual void activate(PluginContainer * container) override;
-    virtual void deactivate() override;
+    virtual void display(GLuint sceneTexture, const glm::uvec2& sceneSize) override;
 
 protected:
-    virtual void customizeWindow(PluginContainer * container) override;
-    virtual void customizeContext(PluginContainer * container) override;
+    virtual GlWindow* createWindow(PluginContainer * container) override final;
+    virtual void customizeWindow(PluginContainer * container) override final;
+    virtual void destroyWindow() override final;
 };
diff --git a/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.cpp
index 2204c0499c..3de57b051b 100644
--- a/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.cpp
+++ b/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.cpp
@@ -49,8 +49,7 @@ QWindow* NullDisplayPlugin::getWindow() const {
 
 void NullDisplayPlugin::preRender() {}
 void NullDisplayPlugin::preDisplay() {}
-void NullDisplayPlugin::display(GLuint sceneTexture, const glm::uvec2& sceneSize,
-    GLuint overlayTexture, const glm::uvec2& overlaySize) {}
+void NullDisplayPlugin::display(GLuint sceneTexture, const glm::uvec2& sceneSize) {}
 void NullDisplayPlugin::finishFrame() {}
 
 void NullDisplayPlugin::activate(PluginContainer * container) {}
diff --git a/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.h
index 123bf55d33..a80ec6567b 100644
--- a/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.h
+++ b/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.h
@@ -29,7 +29,6 @@ public:
     virtual QWindow* getWindow() const;
     virtual void preRender();
     virtual void preDisplay();
-    virtual void display(GLuint sceneTexture, const glm::uvec2& sceneSize,
-        GLuint overlayTexture, const glm::uvec2& overlaySize);
+    virtual void display(GLuint sceneTexture, const glm::uvec2& sceneSize);
     virtual void finishFrame();
 };
diff --git a/libraries/display-plugins/src/display-plugins/OglplusHelpers.h b/libraries/display-plugins/src/display-plugins/OglplusHelpers.h
index b7e9cf9360..535c66ecb4 100644
--- a/libraries/display-plugins/src/display-plugins/OglplusHelpers.h
+++ b/libraries/display-plugins/src/display-plugins/OglplusHelpers.h
@@ -29,12 +29,12 @@
 
 #include <NumericalConstants.h>
 
-typedef std::shared_ptr<oglplus::Framebuffer> FramebufferPtr;
-typedef std::shared_ptr<oglplus::shapes::ShapeWrapper> ShapeWrapperPtr;
-typedef std::shared_ptr<oglplus::Buffer> BufferPtr;
-typedef std::shared_ptr<oglplus::VertexArray> VertexArrayPtr;
-typedef std::shared_ptr<oglplus::Program> ProgramPtr;
-typedef oglplus::Uniform<mat4> Mat4Uniform;
+using FramebufferPtr = std::shared_ptr<oglplus::Framebuffer>;
+using ShapeWrapperPtr = std::shared_ptr<oglplus::shapes::ShapeWrapper>;
+using BufferPtr = std::shared_ptr<oglplus::Buffer>;
+using VertexArrayPtr = std::shared_ptr<oglplus::VertexArray>;
+using ProgramPtr = std::shared_ptr<oglplus::Program>;
+using Mat4Uniform = oglplus::Uniform<mat4>;
 
 ProgramPtr loadDefaultShader();
 void compileProgram(ProgramPtr & result, const std::string& vs, const std::string& fs);
@@ -56,8 +56,8 @@ template <
 struct FramebufferWrapper {
     uvec2       size;
     oglplus::Framebuffer fbo;
-    C           color{ 0 };
-    D           depth{ 0 };
+    C           color;
+    D           depth;
 
     FramebufferWrapper() {}
 
@@ -112,8 +112,7 @@ protected:
     virtual void initDone() = 0;
 };
 
-
-struct BasicFramebufferWrapper : public FramebufferWrapper < oglplus::Texture, oglplus::Renderbuffer > {
+struct BasicFramebufferWrapper : public FramebufferWrapper <oglplus::Texture, oglplus::Renderbuffer> {
 protected:
     virtual void initDepth() override {
         using namespace oglplus;
@@ -131,9 +130,9 @@ protected:
             .WrapS(TextureWrap::ClampToEdge)
             .WrapT(TextureWrap::ClampToEdge)
             .Image2D(
-            0, PixelDataInternalFormat::RGBA8,
-            size.x, size.y,
-            0, PixelDataFormat::RGB, PixelDataType::UnsignedByte, nullptr
+                0, PixelDataInternalFormat::RGBA8,
+                size.x, size.y,
+                0, PixelDataFormat::RGB, PixelDataType::UnsignedByte, nullptr
             );
     }
 
@@ -146,4 +145,6 @@ protected:
             fbo.Complete(target);
         });
     }
-};
\ No newline at end of file
+};
+
+using BasicFramebufferWrapperPtr = std::shared_ptr<BasicFramebufferWrapper>;
\ No newline at end of file
diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp
index 15fccf5941..888cb12654 100644
--- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp
+++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp
@@ -8,11 +8,6 @@
 #include "OpenGLDisplayPlugin.h"
 
 #include <QOpenGLContext>
-#include <TextureCache.h>
-#include <PathUtils.h>
-
-#include <QOpenGLContext>
-#include <QCursor>
 #include <QCoreApplication>
 
 #include <GLWindow.h>
@@ -50,8 +45,6 @@ void OpenGLDisplayPlugin::customizeContext(PluginContainer * container) {
     _program = loadDefaultShader();
     _plane = loadPlane(_program);
     Context::ClearColor(0, 0, 0, 1);
-    _crosshairTexture = DependencyManager::get<TextureCache>()->
-        getImageTexture(PathUtils::resourcesPath() + "images/sixense-reticle.png");
 }
 
 void OpenGLDisplayPlugin::activate(PluginContainer * container) {
@@ -60,11 +53,11 @@ void OpenGLDisplayPlugin::activate(PluginContainer * container) {
 
 void OpenGLDisplayPlugin::deactivate() {
     _timer.stop();
+
     makeCurrent();
     Q_ASSERT(0 == glGetError());
     _plane.reset();
     _program.reset();
-    _crosshairTexture.reset();
     doneCurrent();
 }
 
@@ -109,25 +102,15 @@ bool OpenGLDisplayPlugin::eventFilter(QObject* receiver, QEvent* event) {
 }
 
 void OpenGLDisplayPlugin::display(
-    GLuint sceneTexture, const glm::uvec2& sceneSize,
-    GLuint overlayTexture, const glm::uvec2& overlaySize) {
-    makeCurrent();
-    Q_ASSERT(0 == glGetError());
-    uvec2 size = toGlm(getDeviceSize());
+    GLuint finalTexture, const glm::uvec2& sceneSize) {
     using namespace oglplus;
+
+    uvec2 size = toGlm(getDeviceSize());
     Context::Viewport(size.x, size.y);
-    glClearColor(0, 1, 1, 1);
-    Context::Clear().ColorBuffer().DepthBuffer();
+    Context::Clear().ColorBuffer();
+
     _program->Bind();
-    Mat4Uniform(*_program, "ModelView").Set(mat4());
-    Mat4Uniform(*_program, "Projection").Set(mat4());
-    glBindTexture(GL_TEXTURE_2D, sceneTexture);
+    glBindTexture(GL_TEXTURE_2D, finalTexture);
     _plane->Use();
     _plane->Draw();
-    Context::Enable(Capability::Blend);
-    glBindTexture(GL_TEXTURE_2D, overlayTexture);
-    _plane->Draw();
-    Context::Disable(Capability::Blend);
-    glBindTexture(GL_TEXTURE_2D, 0);
-    Q_ASSERT(0 == glGetError());
 }
diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h
index e4f709b852..7ebc104640 100644
--- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h
+++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h
@@ -9,13 +9,12 @@
 
 #include <QTimer>
 
-#include <gpu/Texture.h>
-
 #include "DisplayPlugin.h"
 #include "OglplusHelpers.h"
 
 class GlWindow;
 class QOpenGLContext;
+
 class OpenGLDisplayPlugin : public DisplayPlugin {
 public:
     OpenGLDisplayPlugin();
@@ -29,9 +28,7 @@ public:
 
     virtual bool eventFilter(QObject* receiver, QEvent* event) override;
 
-    void display(
-        GLuint sceneTexture, const glm::uvec2& sceneSize,
-        GLuint overlayTexture, const glm::uvec2& overlaySize) override;
+    virtual void display(GLuint sceneTexture, const glm::uvec2& sceneSize) override;
 
 protected:
 
@@ -43,10 +40,9 @@ protected:
     virtual void doneCurrent() = 0;
     virtual void swapBuffers() = 0;
 
-    QTimer _timer;
-    ProgramPtr _program;
+    QTimer          _timer;
+    ProgramPtr      _program;
     ShapeWrapperPtr _plane;
-    gpu::TexturePointer _crosshairTexture;
 };
 
 
diff --git a/libraries/display-plugins/src/display-plugins/WidgetOpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/WidgetOpenGLDisplayPlugin.cpp
index 5d75097257..cfd4f5bdf4 100644
--- a/libraries/display-plugins/src/display-plugins/WidgetOpenGLDisplayPlugin.cpp
+++ b/libraries/display-plugins/src/display-plugins/WidgetOpenGLDisplayPlugin.cpp
@@ -17,7 +17,7 @@
 #include <QGLContext>
 #include <QGLWidget>
 #include "plugins/PluginContainer.h"
-
+#if 0
 WidgetOpenGLDisplayPlugin::WidgetOpenGLDisplayPlugin() {
 }
 
@@ -105,4 +105,5 @@ void WidgetOpenGLDisplayPlugin::removeEventFilter(QObject* filter) {
 
 QWindow* WidgetOpenGLDisplayPlugin::getWindow() const {
     return _widget->windowHandle();
-}
\ No newline at end of file
+}
+#endif
\ No newline at end of file
diff --git a/libraries/display-plugins/src/display-plugins/WindowOpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/WindowOpenGLDisplayPlugin.cpp
index ddaf5fae69..3d0dcd19f2 100644
--- a/libraries/display-plugins/src/display-plugins/WindowOpenGLDisplayPlugin.cpp
+++ b/libraries/display-plugins/src/display-plugins/WindowOpenGLDisplayPlugin.cpp
@@ -42,7 +42,7 @@ void WindowOpenGLDisplayPlugin::initSurfaceFormat(QSurfaceFormat& format) {
 
 void WindowOpenGLDisplayPlugin::activate(PluginContainer * container) {
     OpenGLDisplayPlugin::activate(container);
-    _window = new GlWindow(QOpenGLContext::currentContext());
+    _window = createWindow(container);
 
     QSurfaceFormat format;
     initSurfaceFormat(format);
@@ -57,6 +57,14 @@ void WindowOpenGLDisplayPlugin::activate(PluginContainer * container) {
 
 void WindowOpenGLDisplayPlugin::deactivate() {
     OpenGLDisplayPlugin::deactivate();
+    destroyWindow();
+}
+
+GlWindow* WindowOpenGLDisplayPlugin::createWindow(PluginContainer * container) {
+    return new GlWindow(QOpenGLContext::currentContext());
+}
+
+void WindowOpenGLDisplayPlugin::destroyWindow() {
     _window->deleteLater();
     _window = nullptr;
 }
@@ -87,4 +95,4 @@ void WindowOpenGLDisplayPlugin::removeEventFilter(QObject* filter) {
 
 QWindow* WindowOpenGLDisplayPlugin::getWindow() const {
     return _window;
-}
\ No newline at end of file
+}
diff --git a/libraries/display-plugins/src/display-plugins/WindowOpenGLDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/WindowOpenGLDisplayPlugin.h
index 44d5501d59..839fa5d666 100644
--- a/libraries/display-plugins/src/display-plugins/WindowOpenGLDisplayPlugin.h
+++ b/libraries/display-plugins/src/display-plugins/WindowOpenGLDisplayPlugin.h
@@ -28,10 +28,14 @@ public:
     virtual void removeEventFilter(QObject* filter) override;
 
 protected:
+    virtual GlWindow* createWindow(PluginContainer * container);
+    virtual void customizeWindow(PluginContainer * container) = 0;
+
+    virtual void destroyWindow();
+
     virtual void makeCurrent() override;
     virtual void doneCurrent() override;
     virtual void swapBuffers() override;
-    virtual void customizeWindow(PluginContainer * container) = 0;
     virtual void initSurfaceFormat(QSurfaceFormat& format);
 
     GlWindow* _window{ nullptr };
diff --git a/libraries/display-plugins/src/display-plugins/oculus/OculusWin32DisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/oculus/OculusWin32DisplayPlugin.cpp
index 0ec006b6ea..4c7c6a076a 100644
--- a/libraries/display-plugins/src/display-plugins/oculus/OculusWin32DisplayPlugin.cpp
+++ b/libraries/display-plugins/src/display-plugins/oculus/OculusWin32DisplayPlugin.cpp
@@ -30,13 +30,6 @@
 
 #include "../OglplusHelpers.h"
 
-#define DEFAULT_HMD_UI_ANGULAR_SIZE 72.0f
-
-using oglplus::Framebuffer;
-using oglplus::DefaultFramebuffer;
-
-
-
 
 // A base class for FBO wrappers that need to use the Oculus C
 // API to manage textures via ovrHmd_CreateSwapTextureSetGL,
@@ -44,7 +37,10 @@ using oglplus::DefaultFramebuffer;
 template <typename C>
 struct RiftFramebufferWrapper : public FramebufferWrapper<C, char> {
     ovrHmd hmd;
-    RiftFramebufferWrapper(const ovrHmd & hmd) : hmd(hmd) {};
+    RiftFramebufferWrapper(const ovrHmd & hmd) : hmd(hmd) {
+        color = 0;
+        depth = 0;
+    };
 
     void Resize(const uvec2 & size) {
         glBindFramebuffer(GL_DRAW_FRAMEBUFFER, oglplus::GetName(fbo));
@@ -181,6 +177,7 @@ void OculusWin32DisplayPlugin::activate(PluginContainer * container) {
         Q_ASSERT(false);
         qFatal("Failed to acquire HMD");
     }
+
     // Parent class relies on our _hmd intialization, so it must come after that.
     ovrLayerEyeFov& sceneLayer = getSceneLayer();
     memset(&sceneLayer, 0, sizeof(ovrLayerEyeFov));
@@ -200,7 +197,6 @@ void OculusWin32DisplayPlugin::activate(PluginContainer * container) {
     //uiLayer.Header.Flags = ovrLayerFlag_TextureOriginAtBottomLeft | ovrLayerFlag_HighQuality;
     //uiLayer.QuadPoseCenter.Orientation = { 0, 0, 0, 1 };
     //uiLayer.QuadPoseCenter.Position = { 0, 0, -1 };
-
     OculusBaseDisplayPlugin::activate(container);
 }
 
@@ -209,9 +205,6 @@ void OculusWin32DisplayPlugin::customizeContext(PluginContainer * container) {
     
     //_texture = DependencyManager::get<TextureCache>()->
     //    getImageTexture(PathUtils::resourcesPath() + "/images/cube_texture.png");
-
-    _uiSurface = loadSphereSection(_program, glm::radians(DEFAULT_HMD_UI_ANGULAR_SIZE), aspect(getCanvasSize()));
-
     uvec2 mirrorSize = toGlm(_window->geometry().size());
     _mirrorFbo = MirrorFboPtr(new MirrorFramebufferWrapper(_hmd));
     _mirrorFbo->Init(mirrorSize);
@@ -233,7 +226,6 @@ void OculusWin32DisplayPlugin::deactivate() {
     makeCurrent();
     _sceneFbo.reset();
     _mirrorFbo.reset();
-    _uiSurface.reset();
     doneCurrent();
     PerformanceTimer::setActive(false);
 
@@ -244,11 +236,8 @@ void OculusWin32DisplayPlugin::deactivate() {
     ovr_Shutdown();
 }
 
-void OculusWin32DisplayPlugin::display(
-    GLuint sceneTexture, const glm::uvec2& sceneSize,
-    GLuint overlayTexture, const glm::uvec2& overlaySize) {
+void OculusWin32DisplayPlugin::display(GLuint finalTexture, const glm::uvec2& sceneSize) {
     using namespace oglplus;
-
     // Need to make sure only the display plugin is responsible for 
     // controlling vsync
     wglSwapIntervalEXT(0);
@@ -257,68 +246,19 @@ void OculusWin32DisplayPlugin::display(
         auto size = _sceneFbo->size;
         Context::Viewport(size.x, size.y);
 
-        glClearColor(0, 0, 0, 0);
-        Context::Clear().ColorBuffer();
-
         _program->Bind();
         Mat4Uniform(*_program, "Projection").Set(mat4());
         Mat4Uniform(*_program, "ModelView").Set(mat4());
-        glBindTexture(GL_TEXTURE_2D, sceneTexture);
+        glBindTexture(GL_TEXTURE_2D, finalTexture);
         _plane->Use();
         _plane->Draw();
-
-        
-        Context::Enable(Capability::Blend);
-        glBindTexture(GL_TEXTURE_2D, overlayTexture);
-        for_each_eye([&](Eye eye) {
-            Context::Viewport(eye == Left ? 0 : size.x / 2, 0, size.x / 2, size.y);
-            Mat4Uniform(*_program, "Projection").Set(_compositeEyeProjections[eye]);
-            Mat4Uniform(*_program, "ModelView").Set(glm::scale(glm::inverse(getModelview(eye, mat4())), vec3(1)));
-            _uiSurface->Use();
-            _uiSurface->Draw();
-        });
-        Context::Disable(Capability::Blend);
     });
 
-
-    /*
-    An alternative way to render the UI is to pass it specifically as a composition layer to 
-    the Oculus SDK which should technically result in higher quality.  However, the SDK doesn't
-    have a mechanism to present the image as a sphere section, which is our desired look.  
-    */
-#if 0
-    ovrLayerQuad& uiLayer = getUiLayer();
-    if (nullptr == uiLayer.ColorTexture || overlaySize != _uiFbo->size) {
-        _uiFbo->Resize(overlaySize);
-        uiLayer.ColorTexture = _uiFbo->color;
-        uiLayer.Viewport.Size.w = overlaySize.x;
-        uiLayer.Viewport.Size.h = overlaySize.y;
-        float overlayAspect = aspect(overlaySize);
-        uiLayer.QuadSize.x = 1.0f;
-        uiLayer.QuadSize.y = 1.0f / overlayAspect;
-    }
-
-    _uiFbo->Bound([&] {
-        Q_ASSERT(0 == glGetError());
-        using namespace oglplus;
-        Context::Viewport(_uiFbo->size.x, _uiFbo->size.y);
-        glClearColor(0, 0, 0, 0);
-        Context::Clear().ColorBuffer();
-
-        _program->Bind();
-        glBindTexture(GL_TEXTURE_2D, overlayTexture);
-        _plane->Use();
-        _plane->Draw();
-        Q_ASSERT(0 == glGetError());
-    });
-#endif    
-
     ovrLayerEyeFov& sceneLayer = getSceneLayer(); 
     ovr_for_each_eye([&](ovrEyeType eye) {
         sceneLayer.RenderPose[eye] = _eyePoses[eye];
     });
 
-
     auto windowSize = toGlm(getDeviceSize());
 
     /* 
@@ -377,6 +317,39 @@ bool OculusWin32DisplayPlugin::eventFilter(QObject* receiver, QEvent* event) {
     otherwise the swapbuffer delay will interefere with the framerate of the headset
 */
 void OculusWin32DisplayPlugin::finishFrame() {
-    // swapBuffers();
+    swapBuffers();
     doneCurrent();
 };
+
+
+#if 0
+/*
+An alternative way to render the UI is to pass it specifically as a composition layer to
+the Oculus SDK which should technically result in higher quality.  However, the SDK doesn't
+have a mechanism to present the image as a sphere section, which is our desired look.
+*/
+ovrLayerQuad& uiLayer = getUiLayer();
+if (nullptr == uiLayer.ColorTexture || overlaySize != _uiFbo->size) {
+    _uiFbo->Resize(overlaySize);
+    uiLayer.ColorTexture = _uiFbo->color;
+    uiLayer.Viewport.Size.w = overlaySize.x;
+    uiLayer.Viewport.Size.h = overlaySize.y;
+    float overlayAspect = aspect(overlaySize);
+    uiLayer.QuadSize.x = 1.0f;
+    uiLayer.QuadSize.y = 1.0f / overlayAspect;
+}
+
+_uiFbo->Bound([&] {
+    Q_ASSERT(0 == glGetError());
+    using namespace oglplus;
+    Context::Viewport(_uiFbo->size.x, _uiFbo->size.y);
+    glClearColor(0, 0, 0, 0);
+    Context::Clear().ColorBuffer();
+
+    _program->Bind();
+    glBindTexture(GL_TEXTURE_2D, overlayTexture);
+    _plane->Use();
+    _plane->Draw();
+    Q_ASSERT(0 == glGetError());
+});
+#endif    
diff --git a/libraries/display-plugins/src/display-plugins/oculus/OculusWin32DisplayPlugin.h b/libraries/display-plugins/src/display-plugins/oculus/OculusWin32DisplayPlugin.h
index 7e8b16e0b5..8352b0c63a 100644
--- a/libraries/display-plugins/src/display-plugins/oculus/OculusWin32DisplayPlugin.h
+++ b/libraries/display-plugins/src/display-plugins/oculus/OculusWin32DisplayPlugin.h
@@ -26,12 +26,11 @@ public:
     virtual void activate(PluginContainer * container) override;
     virtual void deactivate() override;
 
-    virtual void display(GLuint sceneTexture, const glm::uvec2& sceneSize,
-        GLuint overlayTexture, const glm::uvec2& overlaySize) override;
 
     virtual bool eventFilter(QObject* receiver, QEvent* event) override;
 
 protected:
+    virtual void display(GLuint finalTexture, const glm::uvec2& sceneSize) override;
     virtual void customizeContext(PluginContainer * container) override;
     // Do not perform swap in finish
     virtual void finishFrame() override;
@@ -45,5 +44,4 @@ private:
     SwapFboPtr          _sceneFbo;
     MirrorFboPtr        _mirrorFbo;
     ovrLayerEyeFov      _sceneLayer;
-    ShapeWrapperPtr     _uiSurface;
 };
diff --git a/libraries/display-plugins/src/display-plugins/stereo/InterleavedStereoDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/stereo/InterleavedStereoDisplayPlugin.cpp
index 7af82a01f4..b4e74ef7ba 100644
--- a/libraries/display-plugins/src/display-plugins/stereo/InterleavedStereoDisplayPlugin.cpp
+++ b/libraries/display-plugins/src/display-plugins/stereo/InterleavedStereoDisplayPlugin.cpp
@@ -26,11 +26,6 @@ const QString & InterleavedStereoDisplayPlugin::getName() {
 InterleavedStereoDisplayPlugin::InterleavedStereoDisplayPlugin() {
 }
 
-void InterleavedStereoDisplayPlugin::display(
-    GLuint sceneTexture, const glm::uvec2& sceneSize,
-    GLuint overlayTexture, const glm::uvec2& overlaySize) {
-}
-
 void InterleavedStereoDisplayPlugin::customizeContext(PluginContainer * container) {
     StereoDisplayPlugin::customizeContext(container);
     // Set up the stencil buffers?  Or use a custom shader?
diff --git a/libraries/display-plugins/src/display-plugins/stereo/InterleavedStereoDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/stereo/InterleavedStereoDisplayPlugin.h
index ba7f5f264b..240c09c6b7 100644
--- a/libraries/display-plugins/src/display-plugins/stereo/InterleavedStereoDisplayPlugin.h
+++ b/libraries/display-plugins/src/display-plugins/stereo/InterleavedStereoDisplayPlugin.h
@@ -15,9 +15,6 @@ public:
     InterleavedStereoDisplayPlugin();
     virtual const QString & getName() override;
 
-    virtual void display(GLuint sceneTexture, const glm::uvec2& sceneSize,
-        GLuint overlayTexture, const glm::uvec2& overlaySize) override;
-
     // initialize OpenGL context settings needed by the plugin
     virtual void customizeContext(PluginContainer * container) override;
 
diff --git a/libraries/display-plugins/src/display-plugins/stereo/SideBySideStereoDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/stereo/SideBySideStereoDisplayPlugin.cpp
index 63ce594df4..bc38558822 100644
--- a/libraries/display-plugins/src/display-plugins/stereo/SideBySideStereoDisplayPlugin.cpp
+++ b/libraries/display-plugins/src/display-plugins/stereo/SideBySideStereoDisplayPlugin.cpp
@@ -26,83 +26,3 @@ const QString & SideBySideStereoDisplayPlugin::getName() {
 SideBySideStereoDisplayPlugin::SideBySideStereoDisplayPlugin() {
 }
 
-template <typename F>
-void sbs_for_each_eye(const uvec2& size, F f) {
-    QRect r(QPoint(0, 0), QSize(size.x / 2, size.y));
-    for_each_eye([&](Eye eye) {
-        oglplus::Context::Viewport(r.x(), r.y(), r.width(), r.height());
-        f(eye);
-    }, [&] {
-        r.moveLeft(r.width());
-    });
-}
-
-void SideBySideStereoDisplayPlugin::display(
-    GLuint sceneTexture, const glm::uvec2& sceneSize,
-    GLuint overlayTexture, const glm::uvec2& overlaySize) {
-    makeCurrent();
-    Q_ASSERT(0 == glGetError());
-    uvec2 size = toGlm(getDeviceSize());
-    using namespace oglplus;
-    Context::Viewport(size.x, size.y);
-    Context::Clear().ColorBuffer();
-    
-    _program->Bind();
-    Mat4Uniform(*_program, "ModelView").Set(mat4());
-    Mat4Uniform(*_program, "Projection").Set(mat4());
-
-    glBindTexture(GL_TEXTURE_2D, sceneTexture);
-
-    _plane->Use();
-    _plane->Draw();
-
-    // FIXME the 
-    const float screenAspect = aspect(size);
-    const GLfloat distance = 1.0f;
-    const GLfloat halfQuadHeight = distance * tan(DEFAULT_FIELD_OF_VIEW_DEGREES);
-    const GLfloat halfQuadWidth = halfQuadHeight * screenAspect;
-    const GLfloat quadWidth = halfQuadWidth * 2.0f;
-    const GLfloat quadHeight = halfQuadHeight * 2.0f;
-
-    vec3 quadSize(quadWidth, quadHeight, 1.0f);
-    quadSize = vec3(1.0f) / quadSize;
-
-    using namespace oglplus;
-    Context::Enable(Capability::Blend);
-    glBindTexture(GL_TEXTURE_2D, overlayTexture);
-    
-    mat4 pr = glm::perspective(glm::radians(DEFAULT_FIELD_OF_VIEW_DEGREES), screenAspect, DEFAULT_NEAR_CLIP, DEFAULT_FAR_CLIP);
-    Mat4Uniform(*_program, "Projection").Set(pr);
-
-    // Position the camera relative to the overlay texture
-    MatrixStack mv;
-    mv.translate(vec3(0, 0, -distance)).scale(vec3(0.7f, 0.7f / screenAspect, 1.0f)); // .scale(vec3(quadWidth, quadHeight, 1.0));
-    sbs_for_each_eye(size, [&](Eye eye) {
-        mv.withPush([&] {
-            // translate 
-            mv.top() = getModelview(eye, mv.top());
-            Mat4Uniform(*_program, "ModelView").Set(mv.top());
-            _plane->Draw();
-        });
-    });
-
-    glBindTexture(GL_TEXTURE_2D, gpu::GLBackend::getTextureID(_crosshairTexture));
-    glm::vec2 canvasSize = getCanvasSize();
-    glm::vec2 mouse = toGlm(_window->mapFromGlobal(QCursor::pos()));
-    mouse /= canvasSize;
-    mouse *= 2.0f;
-    mouse -= 1.0f;
-    mouse.y *= -1.0f;
-    sbs_for_each_eye(size, [&](Eye eye) {
-        mv.withPush([&] {
-            // translate 
-            mv.top() = getModelview(eye, mv.top());
-            mv.translate(mouse);
-            //mv.scale(0.05f);
-            mv.scale(vec3(0.025f, 0.05f, 1.0f));
-            Mat4Uniform(*_program, "ModelView").Set(mv.top());
-            _plane->Draw();
-        });
-    });
-    Context::Disable(Capability::Blend);
-}
diff --git a/libraries/display-plugins/src/display-plugins/stereo/SideBySideStereoDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/stereo/SideBySideStereoDisplayPlugin.h
index 4487079387..e052b7f1a1 100644
--- a/libraries/display-plugins/src/display-plugins/stereo/SideBySideStereoDisplayPlugin.h
+++ b/libraries/display-plugins/src/display-plugins/stereo/SideBySideStereoDisplayPlugin.h
@@ -14,9 +14,6 @@ class SideBySideStereoDisplayPlugin : public StereoDisplayPlugin {
 public:
     SideBySideStereoDisplayPlugin();
     virtual const QString & getName() override;
-
-    void display(GLuint sceneTexture, const glm::uvec2& sceneSize,
-        GLuint overlayTexture, const glm::uvec2& overlaySize) override;
 private:
     static const QString NAME;
 };
diff --git a/libraries/plugins/src/plugins/PluginContainer.h b/libraries/plugins/src/plugins/PluginContainer.h
index c6463e949f..687a06567d 100644
--- a/libraries/plugins/src/plugins/PluginContainer.h
+++ b/libraries/plugins/src/plugins/PluginContainer.h
@@ -2,10 +2,10 @@
 
 #include <QString>
 
-class QMainWindow;
+class GlWindow;
 
 class PluginContainer {
 public:
     virtual void addMenuItem(const QString& path, std::function<void()> onClicked, bool checkable = false, bool checked = false, const QString& groupName = "") = 0;
-    virtual QMainWindow* getAppMainWindow() = 0;
+    virtual GlWindow* getVisibleWindow() = 0;
 };