Merge pull request #8164 from SamGondelman/macHMDPreview

Added Mac preview image if VSync is enabled
This commit is contained in:
Brad Hefta-Gaub 2016-07-07 09:01:40 -07:00 committed by GitHub
commit abcd1e0062
7 changed files with 152 additions and 36 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 KiB

View file

@ -16,6 +16,9 @@
#include <QtOpenGL/QGLWidget>
#include <QtGui/QImage>
#if defined(Q_OS_MAC)
#include <OpenGL/CGLCurrent.h>
#endif
#include <gl/QOpenGLContextWrapper.h>
#include <gpu/Texture.h>
#include <gl/GLWidget.h>
@ -612,8 +615,14 @@ void OpenGLDisplayPlugin::enableVsync(bool enable) {
if (!_vsyncSupported) {
return;
}
#ifdef Q_OS_WIN
#if defined(Q_OS_WIN)
wglSwapIntervalEXT(enable ? 1 : 0);
#elif defined(Q_OS_MAC)
GLint interval = enable ? 1 : 0;
CGLSetParameter(CGLGetCurrentContext(), kCGLCPSwapInterval, &interval);
#else
// TODO: Fill in for linux
return;
#endif
}
@ -621,9 +630,14 @@ bool OpenGLDisplayPlugin::isVsyncEnabled() {
if (!_vsyncSupported) {
return true;
}
#ifdef Q_OS_WIN
#if defined(Q_OS_WIN)
return wglGetSwapIntervalEXT() != 0;
#elif defined(Q_OS_MAC)
GLint interval;
CGLGetParameter(CGLGetCurrentContext(), kCGLCPSwapInterval, &interval);
return interval != 0;
#else
// TODO: Fill in for linux
return true;
#endif
}

View file

@ -21,6 +21,11 @@
#include <gl/GLWidget.h>
#include <shared/NsightHelpers.h>
#include <gpu/DrawUnitQuadTexcoord_vert.h>
#include <gpu/DrawTexture_frag.h>
#include <PathUtils.h>
#include "../Logging.h"
#include "../CompositorHelper.h"
@ -58,9 +63,33 @@ bool HmdDisplayPlugin::internalActivate() {
_eyeInverseProjections[eye] = glm::inverse(_eyeProjections[eye]);
});
if (_previewTextureID == 0) {
QImage previewTexture(PathUtils::resourcesPath() + "images/preview.png");
if (!previewTexture.isNull()) {
glGenTextures(1, &_previewTextureID);
glBindTexture(GL_TEXTURE_2D, _previewTextureID);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, previewTexture.width(), previewTexture.height(), 0,
GL_BGRA, GL_UNSIGNED_BYTE, previewTexture.mirrored(false, true).bits());
using namespace oglplus;
Texture::MinFilter(TextureTarget::_2D, TextureMinFilter::Linear);
Texture::MagFilter(TextureTarget::_2D, TextureMagFilter::Linear);
glBindTexture(GL_TEXTURE_2D, 0);
_previewAspect = ((float)previewTexture.width())/((float)previewTexture.height());
_firstPreview = true;
}
}
return Parent::internalActivate();
}
void HmdDisplayPlugin::internalDeactivate() {
if (_previewTextureID != 0) {
glDeleteTextures(1, &_previewTextureID);
_previewTextureID = 0;
}
Parent::internalDeactivate();
}
static const char * REPROJECTION_VS = R"VS(#version 410 core
in vec3 Position;
@ -196,6 +225,7 @@ static ProgramPtr getReprojectionProgram() {
}
#endif
static GLint PREVIEW_TEXTURE_LOCATION = -1;
static const char * LASER_VS = R"VS(#version 410 core
uniform mat4 mvp = mat4(1);
@ -227,14 +257,24 @@ void main() {
void HmdDisplayPlugin::customizeContext() {
Parent::customizeContext();
// Only enable mirroring if we know vsync is disabled
// On Mac, this won't work due to how the contexts are handled, so don't try
#if !defined(Q_OS_MAC)
enableVsync(false);
#endif
_enablePreview = !isVsyncEnabled();
_sphereSection = loadSphereSection(_program, CompositorHelper::VIRTUAL_UI_TARGET_FOV.y, CompositorHelper::VIRTUAL_UI_ASPECT_RATIO);
compileProgram(_laserProgram, LASER_VS, LASER_FS);
_laserGeometry = loadLaser(_laserProgram);
compileProgram(_reprojectionProgram, REPROJECTION_VS, REPROJECTION_FS);
using namespace oglplus;
if (!_enablePreview) {
const std::string version("#version 410 core\n");
compileProgram(_previewProgram, version + DrawUnitQuadTexcoord_vert, version + DrawTexture_frag);
PREVIEW_TEXTURE_LOCATION = Uniform<int>(*_previewProgram, "colorMap").Location();
}
compileProgram(_laserProgram, LASER_VS, LASER_FS);
_laserGeometry = loadLaser(_laserProgram);
compileProgram(_reprojectionProgram, REPROJECTION_VS, REPROJECTION_FS);
REPROJECTION_MATRIX_LOCATION = Uniform<glm::mat3>(*_reprojectionProgram, "reprojection").Location();
INVERSE_PROJECTION_MATRIX_LOCATION = Uniform<glm::mat4>(*_reprojectionProgram, "inverseProjections").Location();
PROJECTION_MATRIX_LOCATION = Uniform<glm::mat4>(*_reprojectionProgram, "projections").Location();
@ -243,6 +283,7 @@ void HmdDisplayPlugin::customizeContext() {
void HmdDisplayPlugin::uncustomizeContext() {
_sphereSection.reset();
_compositeFramebuffer.reset();
_previewProgram.reset();
_reprojectionProgram.reset();
_laserProgram.reset();
_laserGeometry.reset();
@ -335,30 +376,32 @@ void HmdDisplayPlugin::internalPresent() {
hmdPresent();
// screen preview mirroring
auto window = _container->getPrimaryWidget();
auto devicePixelRatio = window->devicePixelRatio();
auto windowSize = toGlm(window->size());
windowSize *= devicePixelRatio;
float windowAspect = aspect(windowSize);
float sceneAspect = _enablePreview ? aspect(_renderTargetSize) : _previewAspect;
if (_enablePreview && _monoPreview) {
sceneAspect /= 2.0f;
}
float aspectRatio = sceneAspect / windowAspect;
uvec2 targetViewportSize = windowSize;
if (aspectRatio < 1.0f) {
targetViewportSize.x *= aspectRatio;
} else {
targetViewportSize.y /= aspectRatio;
}
uvec2 targetViewportPosition;
if (targetViewportSize.x < windowSize.x) {
targetViewportPosition.x = (windowSize.x - targetViewportSize.x) / 2;
} else if (targetViewportSize.y < windowSize.y) {
targetViewportPosition.y = (windowSize.y - targetViewportSize.y) / 2;
}
if (_enablePreview) {
auto window = _container->getPrimaryWidget();
auto windowSize = toGlm(window->size());
float windowAspect = aspect(windowSize);
float sceneAspect = aspect(_renderTargetSize);
if (_monoPreview) {
sceneAspect /= 2.0f;
}
float aspectRatio = sceneAspect / windowAspect;
uvec2 targetViewportSize = windowSize;
if (aspectRatio < 1.0f) {
targetViewportSize.x *= aspectRatio;
} else {
targetViewportSize.y /= aspectRatio;
}
uvec2 targetViewportPosition;
if (targetViewportSize.x < windowSize.x) {
targetViewportPosition.x = (windowSize.x - targetViewportSize.x) / 2;
} else if (targetViewportSize.y < windowSize.y) {
targetViewportPosition.y = (windowSize.y - targetViewportSize.y) / 2;
}
using namespace oglplus;
Context::Clear().ColorBuffer();
auto sourceSize = _compositeFramebuffer->size;
@ -373,6 +416,21 @@ void HmdDisplayPlugin::internalPresent() {
BufferSelectBit::ColorBuffer, BlitFilter::Nearest);
});
swapBuffers();
} else if (_firstPreview || windowSize != _prevWindowSize || devicePixelRatio != _prevDevicePixelRatio) {
useProgram(_previewProgram);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
glClearColor(0, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT);
glViewport(targetViewportPosition.x, targetViewportPosition.y, targetViewportSize.x, targetViewportSize.y);
glUniform1i(PREVIEW_TEXTURE_LOCATION, 0);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, _previewTextureID);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
swapBuffers();
_firstPreview = false;
_prevWindowSize = windowSize;
_prevDevicePixelRatio = devicePixelRatio;
}
postPreview();

View file

@ -40,6 +40,7 @@ protected:
virtual void updatePresentPose();
bool internalActivate() override;
void internalDeactivate() override;
void compositeScene() override;
void compositeOverlay() override;
void compositePointer() override;
@ -89,8 +90,17 @@ private:
bool _enablePreview { false };
bool _monoPreview { true };
bool _enableReprojection { true };
ShapeWrapperPtr _sphereSection;
bool _firstPreview { true };
ProgramPtr _previewProgram;
float _previewAspect { 0 };
GLuint _previewTextureID { 0 };
glm::uvec2 _prevWindowSize { 0, 0 };
qreal _prevDevicePixelRatio { 0 };
ProgramPtr _reprojectionProgram;
ShapeWrapperPtr _sphereSection;
ProgramPtr _laserProgram;
ShapeWrapperPtr _laserGeometry;
};

View file

@ -20,6 +20,7 @@
#include <OpenGL/gl.h>
#include <OpenGL/glext.h>
#include <OpenGL/OpenGL.h>
#endif

View file

@ -47,13 +47,16 @@ void GLWidget::initializeGL() {
// Note, we *DO NOT* want Qt to automatically swap buffers for us. This results in the "ringing" bug mentioned in WL#19514 when we're throttling the framerate.
setAutoBufferSwap(false);
// TODO: write the proper code for linux
makeCurrent();
#if defined(Q_OS_WIN)
if (isValid() && context() && context()->contextHandle()) {
_vsyncSupported = context()->contextHandle()->hasExtension("WGL_EXT_swap_control");;
}
#if defined(Q_OS_WIN)
_vsyncSupported = context()->contextHandle()->hasExtension("WGL_EXT_swap_control");
#elif defined(Q_OS_MAC)
_vsyncSupported = true;
#else
// TODO: write the proper code for linux
#endif
}
}
void GLWidget::paintEvent(QPaintEvent* event) {

View file

@ -68,18 +68,48 @@ bool OculusLegacyDisplayPlugin::isSupported() const {
}
auto hmd = ovrHmd_Create(0);
// The Oculus SDK seems to have trouble finding the right screen sometimes, so we have to guess
// Guesses, in order of best match:
// - resolution and position match
// - resolution and one component of position match
// - resolution matches
// - position matches
// If it still picks the wrong screen, you'll have to mess with your monitor configuration
QList<int> matches({ -1, -1, -1, -1 });
if (hmd) {
QPoint targetPosition{ hmd->WindowsPos.x, hmd->WindowsPos.y };
QSize targetResolution{ hmd->Resolution.w, hmd->Resolution.h };
auto screens = qApp->screens();
for(int i = 0; i < screens.size(); ++i) {
auto screen = screens[i];
QPoint position = screen->geometry().topLeft();
if (position == targetPosition) {
_hmdScreen = i;
break;
QSize resolution = screen->geometry().size();
if (position == targetPosition && resolution == targetResolution) {
matches[0] = i;
} else if ((position.x() == targetPosition.x() || position.y() == targetPosition.y()) &&
resolution == targetResolution) {
matches[1] = i;
} else if (resolution == targetResolution) {
matches[2] = i;
} else if (position == targetPosition) {
matches[3] = i;
}
}
}
for (int screen : matches) {
if (screen != -1) {
_hmdScreen = screen;
break;
}
}
if (_hmdScreen == -1) {
qDebug() << "Could not find Rift screen";
result = false;
}
ovr_Shutdown();
return result;