272 lines · 9.0 KB · C++
RawDownload
////  Created by Bradley Austin Davis on 2018/11/15//  Copyright 2013-2018 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//#include "OculusMobileDisplayPlugin.h" #include <QtAndroidExtras/QAndroidJniEnvironment>#include <glm/gtc/matrix_transform.hpp>#include <VrApi_Types.h>#include <VrApi_Helpers.h> #include <AbstractViewStateInterface.h>#include <gpu/Frame.h>#include <gpu/Context.h>#include <gpu/gl/GLBackend.h>#include <ViewFrustum.h>#include <plugins/PluginManager.h>#include <ui-plugins/PluginContainer.h>#include <controllers/Pose.h>#include <display-plugins/CompositorHelper.h>#include <gpu/Frame.h>#include <gl/Config.h>#include <gl/GLWidget.h>#include <gl/Context.h>#include <MainWindow.h>#include <AddressManager.h> #include <ovr/Helpers.h>#include <VrApi.h> using namespace ovr; const char* OculusMobileDisplayPlugin::NAME { "Oculus Rift" };//thread_local bool renderThread = false;#define OCULUS_APP_ID 2331695256865113 OculusMobileDisplayPlugin::OculusMobileDisplayPlugin() { } OculusMobileDisplayPlugin::~OculusMobileDisplayPlugin() {} void OculusMobileDisplayPlugin::init() {    Parent::init();    initVr();     emit deviceConnected(getName());} void OculusMobileDisplayPlugin::deinit() {    shutdownVr();    Parent::deinit();} bool OculusMobileDisplayPlugin::internalActivate() {    _renderTargetSize = { 1024, 512 };    _cullingProjection = ovr::toGlm(ovrMatrix4f_CreateProjectionFov(90.0f, 90.0f, 0.0f, 0.0f, DEFAULT_NEAR_CLIP, DEFAULT_FAR_CLIP));      withOvrJava([&](const ovrJava* java){        _renderTargetSize = glm::uvec2{            2 * vrapi_GetSystemPropertyInt(java, VRAPI_SYS_PROP_SUGGESTED_EYE_TEXTURE_WIDTH),            vrapi_GetSystemPropertyInt(java, VRAPI_SYS_PROP_SUGGESTED_EYE_TEXTURE_HEIGHT),        };    });     ovr::for_each_eye([&](ovrEye eye){        _eyeProjections[eye] = _cullingProjection;    });     // This must come after the initialization, so that the values calculated    // above are available during the customizeContext call (when not running    // in threaded present mode)    return Parent::internalActivate();} void OculusMobileDisplayPlugin::internalDeactivate() {    Parent::internalDeactivate();    // ovr::releaseRenderSession(_session);} void OculusMobileDisplayPlugin::customizeContext() {    qWarning() << "QQQ" << __FUNCTION__ << "done";    gl::initModuleGl();    _mainContext = _container->getPrimaryWidget()->context();    _mainContext->makeCurrent();    ovr::VrHandler::setHandler(this);    _mainContext->doneCurrent();    _mainContext->makeCurrent();    Parent::customizeContext();    qWarning() << "QQQ" << __FUNCTION__ << "done";} void OculusMobileDisplayPlugin::uncustomizeContext() {    ovr::VrHandler::setHandler(nullptr);    _mainContext->doneCurrent();    _mainContext->makeCurrent();    Parent::uncustomizeContext();} QRectF OculusMobileDisplayPlugin::getPlayAreaRect() {    QRectF result;    VrHandler::withOvrMobile([&](ovrMobile* session){        ovrPosef pose;        ovrVector3f scale;        if (ovrSuccess != vrapi_GetBoundaryOrientedBoundingBox(session, &pose, &scale)) {            return;        }        // FIXME extract the center from the pose        glm::vec2 center { 0 };        glm::vec2 dimensions = glm::vec2(scale.x, scale.z);        dimensions *= 2.0f;        result = QRectF(center.x, center.y, dimensions.x, dimensions.y);    });    return result;} glm::mat4 OculusMobileDisplayPlugin::getEyeProjection(Eye eye, const glm::mat4& baseProjection) const {    glm::mat4 result = baseProjection;     VrHandler::withOvrMobile([&](ovrMobile* session){        auto trackingState = vrapi_GetPredictedTracking2(session, 0.0);        result = ovr::Fov{ trackingState.Eye[eye].ProjectionMatrix }.withZ(baseProjection);    });    return result;} glm::mat4 OculusMobileDisplayPlugin::getCullingProjection(const glm::mat4& baseProjection) const {    glm::mat4 result = baseProjection;     VrHandler::withOvrMobile([&](ovrMobile* session){        auto trackingState = vrapi_GetPredictedTracking2(session, 0.0);        ovr::Fov fovs[2];        for (size_t i = 0; i < 2; ++i) {            fovs[i].extract(trackingState.Eye[i].ProjectionMatrix);        }         fovs[0].extend(fovs[1]);        result= glm::scale( fovs[0].withZ(baseProjection),glm::vec3(1.5f));        return result;    });     return result;} void OculusMobileDisplayPlugin::resetSensors() {    VrHandler::withOvrMobile([&](ovrMobile* session){        vrapi_RecenterPose(session);    });    _currentRenderFrameInfo.renderPose = glm::mat4(); // identity} float OculusMobileDisplayPlugin::getTargetFrameRate() const {    float result = 0.0f;    VrHandler::withOvrJava([&](const ovrJava* java){        result = vrapi_GetSystemPropertyFloat(java, VRAPI_SYS_PROP_DISPLAY_REFRESH_RATE);    });    return result;} bool OculusMobileDisplayPlugin::isHmdMounted() const {    bool result = false;    VrHandler::withOvrJava([&](const ovrJava* java){        result = VRAPI_FALSE != vrapi_GetSystemStatusInt(java, VRAPI_SYS_STATUS_MOUNTED);    });    return result;} static void goToDevMobile() {    auto addressManager = DependencyManager::get<AddressManager>();    auto currentAddress = addressManager->currentAddress().toString().toStdString();    if (std::string::npos == currentAddress.find("quest-dev")) {        addressManager->handleLookupString("hifi://quest-dev");    }} // Called on the render thread, establishes the rough tracking for the upcomingbool OculusMobileDisplayPlugin::beginFrameRender(uint32_t frameIndex) {    static QAndroidJniEnvironment* jniEnv = nullptr;    if (nullptr == jniEnv) {        jniEnv = new QAndroidJniEnvironment();    }    bool result = false;    _currentRenderFrameInfo = FrameInfo();    ovrTracking2 trackingState = {};    static bool resetTrackingTransform = true;    static glm::mat4 transformOffset;     VrHandler::withOvrMobile([&](ovrMobile* session){        if (resetTrackingTransform) {            auto pose = vrapi_GetTrackingTransform( session, VRAPI_TRACKING_TRANSFORM_SYSTEM_CENTER_FLOOR_LEVEL);            transformOffset = glm::inverse(ovr::toGlm(pose));            vrapi_SetTrackingTransform( session, pose);            resetTrackingTransform = false;        }        // Find a better way of        _currentRenderFrameInfo.predictedDisplayTime = vrapi_GetPredictedDisplayTime(session, currentPresentIndex() + 2);        trackingState = vrapi_GetPredictedTracking2(session, _currentRenderFrameInfo.predictedDisplayTime);        result = true;    });       if (result) {        _currentRenderFrameInfo.renderPose = transformOffset;        withNonPresentThreadLock([&] {            _currentRenderFrameInfo.sensorSampleTime = trackingState.HeadPose.TimeInSeconds;            _currentRenderFrameInfo.renderPose = transformOffset * ovr::toGlm(trackingState.HeadPose.Pose);            _currentRenderFrameInfo.presentPose = _currentRenderFrameInfo.renderPose;            _frameInfos[frameIndex] = _currentRenderFrameInfo;            _ipd = vrapi_GetInterpupillaryDistance(&trackingState);            ovr::for_each_eye([&](ovrEye eye){                _eyeProjections[eye] = ovr::toGlm(trackingState.Eye[eye].ProjectionMatrix);                _eyeOffsets[eye] = glm::translate(mat4(), vec3{ _ipd * (eye == VRAPI_EYE_LEFT ? -0.5f : 0.5f), 0.0f, 0.0f });            });       });    }   //  static uint32_t count = 0;  //  if ((++count % 1000) == 0) {  //      AbstractViewStateInterface::instance()->postLambdaEvent([] {  //          goToDevMobile();  //      });  //  }     return result && Parent::beginFrameRender(frameIndex);} ovrTracking2 presentTracking; void OculusMobileDisplayPlugin::updatePresentPose() {    static QAndroidJniEnvironment* jniEnv = nullptr;    if (nullptr == jniEnv) {        jniEnv = new QAndroidJniEnvironment();    }    VrHandler::withOvrMobile([&](ovrMobile* session){        presentTracking = beginFrame();        _currentPresentFrameInfo.sensorSampleTime = vrapi_GetTimeInSeconds();        _currentPresentFrameInfo.predictedDisplayTime = presentTracking.HeadPose.TimeInSeconds;        _currentPresentFrameInfo.presentPose = ovr::toGlm(presentTracking.HeadPose.Pose);    });} void OculusMobileDisplayPlugin::internalPresent() {    VrHandler::pollTask();     if (!vrActive()) {        QThread::msleep(1);        return;    }     auto sourceTexture = getGLBackend()->getTextureID(_compositeFramebuffer->getRenderBuffer(0));    glm::uvec2 sourceSize{ _compositeFramebuffer->getWidth(), _compositeFramebuffer->getHeight() };    VrHandler::presentFrame(sourceTexture, sourceSize, presentTracking);    _presentRate.increment();} DisplayPluginList getDisplayPlugins() {    static DisplayPluginList result;    static std::once_flag once;    std::call_once(once, [&]{        auto plugin = std::make_shared<OculusMobileDisplayPlugin>();        plugin->isSupported();        result.push_back(plugin);    });    return result;}