diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index 3ce033f27..a4cb21c49 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -87,6 +87,8 @@ target_sources( native-lib PUBLIC src/oculusvr/cpp/DeviceDelegateOculusVR.cpp + src/oculusvr/cpp/OculusSwapChain.cpp + src/oculusvr/cpp/OculusVRLayers.cpp ) add_custom_command(TARGET native-lib POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy diff --git a/app/src/oculusvr/cpp/DeviceDelegateOculusVR.cpp b/app/src/oculusvr/cpp/DeviceDelegateOculusVR.cpp index 3ac49dc44..ceca1d624 100644 --- a/app/src/oculusvr/cpp/DeviceDelegateOculusVR.cpp +++ b/app/src/oculusvr/cpp/DeviceDelegateOculusVR.cpp @@ -4,6 +4,8 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "DeviceDelegateOculusVR.h" +#include "OculusSwapChain.h" +#include "OculusVRLayers.h" #include "DeviceUtils.h" #include "ElbowModel.h" #include "BrowserEGLContext.h" @@ -41,595 +43,6 @@ namespace crow { -static ovrMatrix4f ovrMatrixFrom(const vrb::Matrix& aMatrix) { - ovrMatrix4f m; - m.M[0][0] = aMatrix.At(0, 0); - m.M[0][1] = aMatrix.At(1, 0); - m.M[0][2] = aMatrix.At(2, 0); - m.M[0][3] = aMatrix.At(3, 0); - m.M[1][0] = aMatrix.At(0, 1); - m.M[1][1] = aMatrix.At(1, 1); - m.M[1][2] = aMatrix.At(2, 1); - m.M[1][3] = aMatrix.At(3, 1); - m.M[2][0] = aMatrix.At(0, 2); - m.M[2][1] = aMatrix.At(1, 2); - m.M[2][2] = aMatrix.At(2, 2); - m.M[2][3] = aMatrix.At(3, 2); - m.M[3][0] = aMatrix.At(0, 3); - m.M[3][1] = aMatrix.At(1, 3); - m.M[3][2] = aMatrix.At(2, 3); - m.M[3][3] = aMatrix.At(3, 3); - return m; -} - -class OculusEyeSwapChain; - -typedef std::shared_ptr OculusEyeSwapChainPtr; - -struct OculusEyeSwapChain { - ovrTextureSwapChain *ovrSwapChain = nullptr; - int swapChainLength = 0; - std::vector fbos; - - static OculusEyeSwapChainPtr create() { - return std::make_shared(); - } - - void Init(vrb::RenderContextPtr &aContext, device::RenderMode aMode, uint32_t aWidth, - uint32_t aHeight) { - Destroy(); - ovrSwapChain = vrapi_CreateTextureSwapChain(VRAPI_TEXTURE_TYPE_2D, - VRAPI_TEXTURE_FORMAT_8888, - aWidth, aHeight, 1, true); - swapChainLength = vrapi_GetTextureSwapChainLength(ovrSwapChain); - - for (int i = 0; i < swapChainLength; ++i) { - vrb::FBOPtr fbo = vrb::FBO::Create(aContext); - auto texture = vrapi_GetTextureSwapChainHandle(ovrSwapChain, i); - VRB_GL_CHECK(glBindTexture(GL_TEXTURE_2D, texture)); - VRB_GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); - VRB_GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); - VRB_GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); - VRB_GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); - - vrb::FBO::Attributes attributes; - if (aMode == device::RenderMode::Immersive) { - attributes.depth = true; - attributes.samples = 0; - } else { - attributes.depth = true; - attributes.samples = 4; - } - - VRB_GL_CHECK(fbo->SetTextureHandle(texture, aWidth, aHeight, attributes)); - if (fbo->IsValid()) { - fbos.push_back(fbo); - } else { - VRB_LOG("FAILED to make valid FBO"); - } - } - } - - void Destroy() { - fbos.clear(); - if (ovrSwapChain) { - vrapi_DestroyTextureSwapChain(ovrSwapChain); - ovrSwapChain = nullptr; - } - swapChainLength = 0; - } -}; - - -class OculusLayer; -typedef std::shared_ptr OculusLayerPtr; - -struct SurfaceChangedTarget { - OculusLayer * layer; - SurfaceChangedTarget(OculusLayer * aLayer): layer(aLayer) {}; -}; - -typedef std::shared_ptr SurfaceChangedTargetPtr; -typedef std::weak_ptr SurfaceChangedTargetWeakPtr; - -class OculusLayer { -public: - virtual void Init(JNIEnv * aEnv, vrb::RenderContextPtr& aContext) = 0; - virtual void Update(const ovrTracking2& aTracking, ovrTextureSwapChain* aClearSwapChain) = 0; - virtual ovrTextureSwapChain * GetSwapChain() const = 0; - virtual const ovrLayerHeader2 * Header() const = 0; - virtual void SetCurrentEye(device::Eye aEye) = 0; - virtual bool IsDrawRequested() const = 0; - virtual bool GetDrawInFront() const = 0; - virtual void ClearRequestDraw() = 0; - virtual bool IsComposited() const = 0; - virtual void SetComposited(bool aValue) = 0; - virtual VRLayerPtr GetLayer() const = 0; - virtual void Destroy() = 0; - typedef std::function BindDelegate; - virtual void SetBindDelegate(const BindDelegate& aDelegate) = 0; - virtual jobject GetSurface() const = 0; - virtual SurfaceChangedTargetPtr GetSurfaceChangedTarget() const = 0; - virtual void HandleResize(ovrTextureSwapChain * newSwapChain, jobject newSurface, vrb::FBOPtr newFBO) = 0; - virtual ~OculusLayer() {} -}; - -template -class OculusLayerBase: public OculusLayer { -public: - ovrTextureSwapChain * swapChain = nullptr; - SurfaceChangedTargetPtr surfaceChangedTarget; - T layer; - U ovrLayer; - - void Init(JNIEnv * aEnv, vrb::RenderContextPtr& aContext) override { - layer->SetInitialized(true); - surfaceChangedTarget = std::make_shared(this); - SurfaceChangedTargetWeakPtr weakTarget = surfaceChangedTarget; - layer->NotifySurfaceChanged(VRLayer::SurfaceChange::Create, [=]() { - SurfaceChangedTargetPtr target = weakTarget.lock(); - if (target) { - target->layer->SetComposited(true); - } - }); - } - - virtual void Update(const ovrTracking2& aTracking, ovrTextureSwapChain* aClearSwapChain) override{ - vrb::Color tintColor = layer->GetTintColor(); - if (!IsComposited() && layer->GetClearColor().Alpha()) { - tintColor = layer->GetClearColor(); - } - ovrLayer.Header.ColorScale.x = tintColor.Red(); - ovrLayer.Header.ColorScale.y = tintColor.Green(); - ovrLayer.Header.ColorScale.z = tintColor.Blue(); - ovrLayer.Header.ColorScale.w = tintColor.Alpha(); - } - - virtual ovrTextureSwapChain * GetSwapChain() const override { - return swapChain; - } - - const ovrLayerHeader2 * Header() const override { - return &ovrLayer.Header; - } - - void SetCurrentEye(device::Eye aEye) override { - layer->SetCurrentEye(aEye); - } - - virtual bool IsDrawRequested() const override { - return layer->IsDrawRequested() && ((swapChain && IsComposited()) || layer->GetClearColor().Alpha() > 0.0f); - } - - bool GetDrawInFront() const override { - return layer->GetDrawInFront(); - } - - void ClearRequestDraw() override { - layer->ClearRequestDraw(); - } - - bool IsComposited() const override { - return layer->IsComposited(); - } - - void SetComposited(bool aValue) override { - layer->SetComposited(aValue); - } - - VRLayerPtr GetLayer() const override { - return layer; - } - - void SetClipEnabled(bool aEnabled) { - if (aEnabled) { - ovrLayer.Header.Flags |= VRAPI_FRAME_LAYER_FLAG_CLIP_TO_TEXTURE_RECT; - } else { - ovrLayer.Header.Flags &= ~VRAPI_FRAME_LAYER_FLAG_CLIP_TO_TEXTURE_RECT; - } - } - - void Destroy() override { - if (swapChain != nullptr) { - vrapi_DestroyTextureSwapChain(swapChain); - swapChain = nullptr; - } - layer->SetInitialized(false); - SetComposited(false); - layer->NotifySurfaceChanged(VRLayer::SurfaceChange::Destroy, nullptr); - } - - void SetBindDelegate(const BindDelegate& aDelegate) override {} - - jobject GetSurface() const override { - return nullptr; - } - - SurfaceChangedTargetPtr GetSurfaceChangedTarget() const override { - return surfaceChangedTarget; - } - - void HandleResize(ovrTextureSwapChain * newSwapChain, jobject newSurface, vrb::FBOPtr newFBO) override {} - - ovrTextureSwapChain* GetTargetSwapChain(ovrTextureSwapChain* aClearSwapChain) { - return (IsComposited() || layer->GetClearColor().Alpha() == 0) ? swapChain : aClearSwapChain; - } - - virtual ~OculusLayerBase() {} -}; - - -template -class OculusLayerSurface: public OculusLayerBase { -public: - jobject surface = nullptr; - vrb::FBOPtr fbo; - vrb::RenderContextWeak contextWeak; - JNIEnv * jniEnv = nullptr; - OculusLayer::BindDelegate bindDelegate; - - void Init(JNIEnv * aEnv, vrb::RenderContextPtr& aContext) override { - this->jniEnv = aEnv; - this->contextWeak = aContext; - this->ovrLayer.Header.SrcBlend = VRAPI_FRAME_LAYER_BLEND_ONE; - this->ovrLayer.Header.DstBlend = VRAPI_FRAME_LAYER_BLEND_ONE_MINUS_SRC_ALPHA; - if (this->swapChain) { - return; - } - - InitSwapChain(this->swapChain, this->surface, this->fbo); - this->layer->SetResizeDelegate([=]{ - Resize(); - }); - OculusLayerBase::Init(aEnv, aContext); - } - - void Resize() { - if (!this->swapChain) { - return; - } - // Delay the destruction of the current swapChain until the new one is composited. - // This is required to prevent a black flicker when resizing. - ovrTextureSwapChain * newSwapChain = nullptr; - jobject newSurface = nullptr; - vrb::FBOPtr newFBO; - InitSwapChain(newSwapChain, newSurface, newFBO); - this->layer->SetSurface(newSurface); - - SurfaceChangedTargetWeakPtr weakTarget = this->surfaceChangedTarget; - this->layer->NotifySurfaceChanged(VRLayer::SurfaceChange::Create, [=]() { - SurfaceChangedTargetPtr target = weakTarget.lock(); - if (target && target->layer) { - target->layer->HandleResize(newSwapChain, newSurface, newFBO); - } - }); - } - - void HandleResize(ovrTextureSwapChain * newSwapChain, jobject newSurface, vrb::FBOPtr newFBO) override { - if (this->swapChain) { - vrapi_DestroyTextureSwapChain(this->swapChain); - } - if (this->surface) { - jniEnv->DeleteGlobalRef(this->surface); - } - this->swapChain = newSwapChain; - this->surface = newSurface; - this->fbo = newFBO; - this->SetComposited(true); - } - - void Destroy() override { - this->fbo = nullptr; - if (this->surface) { - this->jniEnv->DeleteGlobalRef(surface); - this->surface = nullptr; - this->layer->SetSurface(nullptr); - } - OculusLayerBase::Destroy(); - } - - void SetBindDelegate(const OculusLayer::BindDelegate& aDelegate) override { - bindDelegate = aDelegate; - this->layer->SetBindDelegate([=](GLenum aTarget, bool aBind) { - if (bindDelegate) { - bindDelegate(this->fbo, aTarget, aBind); - } - }); - } - - virtual jobject GetSurface() const override { - return surface; - } - -protected: - void TakeSurface(const OculusLayerPtr& aSource) { - this->swapChain = aSource->GetSwapChain(); - this->surface = aSource->GetSurface(); - this->surfaceChangedTarget = aSource->GetSurfaceChangedTarget(); - if (this->surfaceChangedTarget) { - // Indicate that the first composite notification should be notified to this layer. - this->surfaceChangedTarget->layer = this; - } - this->SetComposited(aSource->IsComposited()); - this->layer->SetInitialized(aSource->GetLayer()->IsInitialized()); - this->layer->SetResizeDelegate([=]{ - Resize(); - }); - } -private: - void InitSwapChain(ovrTextureSwapChain*& swapChainOut, jobject & surfaceOut, vrb::FBOPtr& fboOut) { - if (this->layer->GetSurfaceType() == VRLayerQuad::SurfaceType::AndroidSurface) { - swapChainOut = vrapi_CreateAndroidSurfaceSwapChain(this->layer->GetWidth(), this->layer->GetHeight()); - surfaceOut = vrapi_GetTextureSwapChainAndroidSurface(swapChainOut); - surfaceOut = this->jniEnv->NewGlobalRef(surfaceOut); - this->layer->SetSurface(surface); - } else { - swapChainOut = vrapi_CreateTextureSwapChain(VRAPI_TEXTURE_TYPE_2D, VRAPI_TEXTURE_FORMAT_8888, - this->layer->GetWidth(), this->layer->GetHeight(), 1, false); - vrb::RenderContextPtr ctx = this->contextWeak.lock(); - fboOut = vrb::FBO::Create(ctx); - GLuint texture = vrapi_GetTextureSwapChainHandle(swapChainOut, 0); - VRB_GL_CHECK(glBindTexture(GL_TEXTURE_2D, texture)); - VRB_GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); - VRB_GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); - VRB_GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); - VRB_GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); - vrb::FBO::Attributes attributes; - attributes.depth = false; - attributes.samples = 0; - VRB_GL_CHECK(fboOut->SetTextureHandle(texture, this->layer->GetWidth(), this->layer->GetHeight(), attributes)); - if (fboOut->IsValid()) { - fboOut->Bind(); - VRB_GL_CHECK(glClearColor(0.0f, 0.0f, 0.0f, 0.0f)); - VRB_GL_CHECK(glClear(GL_COLOR_BUFFER_BIT)); - fboOut->Unbind(); - } else { - VRB_WARN("FAILED to make valid FBO for OculusLayerSurface"); - } - } - } - -}; - -class OculusLayerQuad; -typedef std::shared_ptr OculusLayerQuadPtr; - -class OculusLayerQuad: public OculusLayerSurface { -public: - static OculusLayerQuadPtr Create(const VRLayerQuadPtr& aLayer, const OculusLayerPtr& aSource = nullptr) { - auto result = std::make_shared(); - result->layer = aLayer; - if (aSource) { - result->TakeSurface(aSource); - } - return result; - } - - void Init(JNIEnv * aEnv, vrb::RenderContextPtr& aContext) override { - ovrLayer = vrapi_DefaultLayerProjection2(); - OculusLayerSurface::Init(aEnv, aContext); - } - - void Update(const ovrTracking2& aTracking, ovrTextureSwapChain* aClearSwapChain) override { - OculusLayerSurface::Update(aTracking, aClearSwapChain); - const float w = layer->GetWorldWidth(); - const float h = layer->GetWorldHeight(); - - vrb::Matrix scale = vrb::Matrix::Identity(); - scale.ScaleInPlace(vrb::Vector(w * 0.5f, h * 0.5f, 1.0f)); - - bool clip = false; - - for (int i = 0; i < VRAPI_FRAME_LAYER_EYE_MAX; ++i) { - device::Eye eye = i == 0 ? device::Eye::Left : device::Eye::Right; - vrb::Matrix matrix = layer->GetView(eye).PostMultiply(layer->GetModelTransform(eye)); - matrix.PostMultiplyInPlace(scale); - ovrMatrix4f modelView = ovrMatrixFrom(matrix); - - device::EyeRect textureRect = layer->GetTextureRect(eye); - - ovrLayer.Textures[i].ColorSwapChain = GetTargetSwapChain(aClearSwapChain); - ovrLayer.Textures[i].SwapChainIndex = 0; - ovrLayer.Textures[i].TexCoordsFromTanAngles = ovrMatrix4f_TanAngleMatrixFromUnitSquare(&modelView); - ovrLayer.Textures[i].TextureRect.x = textureRect.mX; - ovrLayer.Textures[i].TextureRect.y = textureRect.mY; - ovrLayer.Textures[i].TextureRect.width = textureRect.mWidth; - ovrLayer.Textures[i].TextureRect.height = textureRect.mHeight; - clip = clip || !textureRect.IsDefault(); - } - SetClipEnabled(clip); - - ovrLayer.HeadPose = aTracking.HeadPose; - } -}; - -class OculusLayerCylinder; -typedef std::shared_ptr OculusLayerCylinderPtr; - -class OculusLayerCylinder: public OculusLayerSurface { -public: - static OculusLayerCylinderPtr Create(const VRLayerCylinderPtr& aLayer, const OculusLayerPtr& aSource = nullptr) { - auto result = std::make_shared(); - result->layer = aLayer; - if (aSource) { - result->TakeSurface(aSource); - } - return result; - } - - void Init(JNIEnv * aEnv, vrb::RenderContextPtr& aContext) override { - ovrLayer = vrapi_DefaultLayerCylinder2(); - OculusLayerSurface::Init(aEnv, aContext); - } - - void Update(const ovrTracking2& aTracking, ovrTextureSwapChain* aClearSwapChain) override { - OculusLayerSurface::Update(aTracking, aClearSwapChain); - const float w = layer->GetWorldWidth(); - const float h = layer->GetWorldHeight(); - - ovrLayer.HeadPose = aTracking.HeadPose; - ovrLayer.Header.SrcBlend = VRAPI_FRAME_LAYER_BLEND_ONE; - ovrLayer.Header.DstBlend = VRAPI_FRAME_LAYER_BLEND_ONE_MINUS_SRC_ALPHA; - - for ( int i = 0; i < VRAPI_FRAME_LAYER_EYE_MAX; i++ ) { - device::Eye eye = i == 0 ? device::Eye::Left : device::Eye::Right; - vrb::Matrix modelView = layer->GetView(eye).PostMultiply(layer->GetModelTransform(eye)); - ovrMatrix4f matrix = ovrMatrixFrom(modelView); - ovrLayer.Textures[i].TexCoordsFromTanAngles = ovrMatrix4f_Inverse(&matrix); - ovrLayer.Textures[i].ColorSwapChain = GetTargetSwapChain(aClearSwapChain); - ovrLayer.Textures[i].SwapChainIndex = 0; - - const vrb::Vector scale = layer->GetUVTransform(eye).GetScale(); - const vrb::Vector translation = layer->GetUVTransform(eye).GetTranslation(); - - ovrLayer.Textures[i].TextureMatrix.M[0][0] = scale.x(); - ovrLayer.Textures[i].TextureMatrix.M[1][1] = scale.y(); - ovrLayer.Textures[i].TextureMatrix.M[0][2] = translation.x(); - ovrLayer.Textures[i].TextureMatrix.M[1][2] = translation.y(); - - ovrLayer.Textures[i].TextureRect.width = 1.0f; - ovrLayer.Textures[i].TextureRect.height = 1.0f; - } - } -}; - -class OculusLayerCube; -typedef std::shared_ptr OculusLayerCubePtr; - -class OculusLayerCube: public OculusLayerBase { -public: - static OculusLayerCubePtr Create(const VRLayerCubePtr& aLayer, GLint aInternalFormat) { - auto result = std::make_shared(); - result->layer = aLayer; - result->glFormat = aInternalFormat; - return result; - } - - void Init(JNIEnv * aEnv, vrb::RenderContextPtr& aContext) override { - if (swapChain) { - return; - } - - ovrLayer = vrapi_DefaultLayerCube2(); - ovrLayer.Offset.x = 0.0f; - ovrLayer.Offset.y = 0.0f; - ovrLayer.Offset.z = 0.0f; - swapChain = vrapi_CreateTextureSwapChain3(VRAPI_TEXTURE_TYPE_CUBE, glFormat, layer->GetWidth(), layer->GetHeight(), 1, 1); - layer->SetTextureHandle(vrapi_GetTextureSwapChainHandle(swapChain, 0)); - OculusLayerBase::Init(aEnv, aContext); - } - - void Destroy() override { - if (swapChain == nullptr) { - return; - } - layer->SetTextureHandle(0); - layer->SetLoaded(false); - OculusLayerBase::Destroy(); - } - - bool IsLoaded() const { - return layer->IsLoaded(); - } - - void Update(const ovrTracking2& aTracking, ovrTextureSwapChain* aClearSwapChain) override { - OculusLayerBase::Update(aTracking, aClearSwapChain); - const ovrMatrix4f centerEyeViewMatrix = vrapi_GetViewMatrixFromPose(&aTracking.HeadPose.Pose); - const ovrMatrix4f cubeMatrix = ovrMatrix4f_TanAngleMatrixForCubeMap(¢erEyeViewMatrix); - ovrLayer.HeadPose = aTracking.HeadPose; - ovrLayer.TexCoordsFromTanAngles = cubeMatrix; - - for (int i = 0; i < VRAPI_FRAME_LAYER_EYE_MAX; ++i) { - ovrLayer.Textures[i].ColorSwapChain = GetTargetSwapChain(aClearSwapChain); - ovrLayer.Textures[i].SwapChainIndex = 0; - } - } - -protected: - GLint glFormat; -}; - - -class OculusLayerEquirect; -typedef std::shared_ptr OculusLayerEquirectPtr; - -class OculusLayerEquirect: public OculusLayerBase { -public: - std::weak_ptr sourceLayer; - - static OculusLayerEquirectPtr Create(const VRLayerEquirectPtr& aLayer, const OculusLayerPtr& aSourceLayer) { - auto result = std::make_shared(); - result->layer = aLayer; - result->sourceLayer = aSourceLayer; - return result; - } - - void Init(JNIEnv * aEnv, vrb::RenderContextPtr& aContext) override { - OculusLayerPtr source = sourceLayer.lock(); - if (!source) { - return; - } - - swapChain = source->GetSwapChain(); - ovrLayer = vrapi_DefaultLayerEquirect2(); - ovrLayer.HeadPose.Pose.Position.x = 0.0f; - ovrLayer.HeadPose.Pose.Position.y = 0.0f; - ovrLayer.HeadPose.Pose.Position.z = 0.0f; - ovrLayer.HeadPose.Pose.Orientation.x = 0.0f; - ovrLayer.HeadPose.Pose.Orientation.y = 0.0f; - ovrLayer.HeadPose.Pose.Orientation.z = 0.0f; - ovrLayer.HeadPose.Pose.Orientation.w = 1.0f; - ovrLayer.TexCoordsFromTanAngles = ovrMatrix4f_CreateIdentity(); - OculusLayerBase::Init(aEnv, aContext); - } - - void Destroy() override { - swapChain = nullptr; - OculusLayerBase::Destroy(); - } - - bool IsDrawRequested() const override { - OculusLayerPtr source = sourceLayer.lock(); - return source && source->GetSwapChain() && source->IsComposited() && layer->IsDrawRequested(); - } - - void Update(const ovrTracking2& aTracking, ovrTextureSwapChain* aClearSwapChain) override { - OculusLayerPtr source = sourceLayer.lock(); - if (source) { - swapChain = source->GetSwapChain(); - } - OculusLayerBase::Update(aTracking, aClearSwapChain); - - vrb::Quaternion q(layer->GetModelTransform(device::Eye::Left)); - ovrLayer.HeadPose.Pose.Orientation.x = q.x(); - ovrLayer.HeadPose.Pose.Orientation.y = q.y(); - ovrLayer.HeadPose.Pose.Orientation.z = q.z(); - ovrLayer.HeadPose.Pose.Orientation.w = q.w(); - - bool clip = false; - for (int i = 0; i < VRAPI_FRAME_LAYER_EYE_MAX; ++i) { - const device::Eye eye = i == 0 ? device::Eye::Left : device::Eye::Right; - ovrLayer.Textures[i].ColorSwapChain = GetTargetSwapChain(aClearSwapChain); - ovrLayer.Textures[i].SwapChainIndex = 0; - const vrb::Vector scale = layer->GetUVTransform(eye).GetScale(); - const vrb::Vector translation = layer->GetUVTransform(eye).GetTranslation(); - - ovrLayer.Textures[i].TextureMatrix.M[0][0] = scale.x(); - ovrLayer.Textures[i].TextureMatrix.M[1][1] = scale.y(); - ovrLayer.Textures[i].TextureMatrix.M[0][2] = translation.x(); - ovrLayer.Textures[i].TextureMatrix.M[1][2] = translation.y(); - - device::EyeRect textureRect = layer->GetTextureRect(eye); - ovrLayer.Textures[i].TextureRect.x = textureRect.mX; - ovrLayer.Textures[i].TextureRect.y = textureRect.mY; - ovrLayer.Textures[i].TextureRect.width = textureRect.mWidth; - ovrLayer.Textures[i].TextureRect.height = textureRect.mHeight; - clip = clip || !textureRect.IsDefault(); - } - SetClipEnabled(clip); - } -}; - const vrb::Vector kAverageHeight(0.0f, 1.7f, 0.0f); // Height used to match Oculus default in WebVR const vrb::Vector kAverageOculusHeight(0.0f, 1.65f, 0.0f); diff --git a/app/src/oculusvr/cpp/OculusSwapChain.cpp b/app/src/oculusvr/cpp/OculusSwapChain.cpp new file mode 100644 index 000000000..746eb5e73 --- /dev/null +++ b/app/src/oculusvr/cpp/OculusSwapChain.cpp @@ -0,0 +1,59 @@ +#include "OculusSwapChain.h" +#include "vrb/FBO.h" +#include "vrb/GLError.h" +#include "vrb/Logger.h" + +namespace crow { + +OculusEyeSwapChainPtr +OculusEyeSwapChain::create() { + return std::make_shared(); +} + +void +OculusEyeSwapChain::Init(vrb::RenderContextPtr &aContext, device::RenderMode aMode, uint32_t aWidth, + uint32_t aHeight) { + Destroy(); + ovrSwapChain = vrapi_CreateTextureSwapChain(VRAPI_TEXTURE_TYPE_2D, + VRAPI_TEXTURE_FORMAT_8888, + aWidth, aHeight, 1, true); + swapChainLength = vrapi_GetTextureSwapChainLength(ovrSwapChain); + + for (int i = 0; i < swapChainLength; ++i) { + vrb::FBOPtr fbo = vrb::FBO::Create(aContext); + auto texture = vrapi_GetTextureSwapChainHandle(ovrSwapChain, i); + VRB_GL_CHECK(glBindTexture(GL_TEXTURE_2D, texture)); + VRB_GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); + VRB_GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); + VRB_GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); + VRB_GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); + + vrb::FBO::Attributes attributes; + if (aMode == device::RenderMode::Immersive) { + attributes.depth = true; + attributes.samples = 0; + } else { + attributes.depth = true; + attributes.samples = 4; + } + + VRB_GL_CHECK(fbo->SetTextureHandle(texture, aWidth, aHeight, attributes)); + if (fbo->IsValid()) { + fbos.push_back(fbo); + } else { + VRB_LOG("FAILED to make valid FBO"); + } + } +} + +void +OculusEyeSwapChain::Destroy() { + fbos.clear(); + if (ovrSwapChain) { + vrapi_DestroyTextureSwapChain(ovrSwapChain); + ovrSwapChain = nullptr; + } + swapChainLength = 0; +} + +} diff --git a/app/src/oculusvr/cpp/OculusSwapChain.h b/app/src/oculusvr/cpp/OculusSwapChain.h new file mode 100644 index 000000000..e4b294b3a --- /dev/null +++ b/app/src/oculusvr/cpp/OculusSwapChain.h @@ -0,0 +1,26 @@ +#pragma once + +#include "vrb/Forward.h" +#include "Device.h" +#include "VrApi.h" +#include +#include + +namespace crow { + +class OculusEyeSwapChain; + +typedef std::shared_ptr OculusEyeSwapChainPtr; + +class OculusEyeSwapChain { +public: + ovrTextureSwapChain *ovrSwapChain = nullptr; + int swapChainLength = 0; + std::vector fbos; + + static OculusEyeSwapChainPtr create(); + void Init(vrb::RenderContextPtr &aContext, device::RenderMode aMode, uint32_t aWidth, uint32_t aHeight); + void Destroy(); +}; + +} diff --git a/app/src/oculusvr/cpp/OculusVRLayers.cpp b/app/src/oculusvr/cpp/OculusVRLayers.cpp new file mode 100644 index 000000000..f8ea8a6e0 --- /dev/null +++ b/app/src/oculusvr/cpp/OculusVRLayers.cpp @@ -0,0 +1,246 @@ +#include "OculusVRLayers.h" + +namespace crow { + +static ovrMatrix4f ovrMatrixFrom(const vrb::Matrix &aMatrix) { + ovrMatrix4f m; + for (int32_t i = 0; i < 16; ++i) { + const int32_t row = i / 4; + const int32_t col = i % 4; + m.M[row][col] = aMatrix.At(col, row); + } + return m; +} + + +// OculusLayerQuad + +OculusLayerQuadPtr +OculusLayerQuad::Create(const VRLayerQuadPtr& aLayer, const OculusLayerPtr& aSource) { + auto result = std::make_shared(); + result->layer = aLayer; + if (aSource) { + result->TakeSurface(aSource); + } + return result; +} + +void +OculusLayerQuad::Init(JNIEnv * aEnv, vrb::RenderContextPtr& aContext) { + ovrLayer = vrapi_DefaultLayerProjection2(); + OculusLayerSurface::Init(aEnv, aContext); +} + +void +OculusLayerQuad::Update(const ovrTracking2& aTracking, ovrTextureSwapChain* aClearSwapChain) { + const float w = layer->GetWorldWidth(); + const float h = layer->GetWorldHeight(); + + vrb::Matrix scale = vrb::Matrix::Identity(); + scale.ScaleInPlace(vrb::Vector(w * 0.5f, h * 0.5f, 1.0f)); + + bool clip = false; + + for (int i = 0; i < VRAPI_FRAME_LAYER_EYE_MAX; ++i) { + device::Eye eye = i == 0 ? device::Eye::Left : device::Eye::Right; + vrb::Matrix matrix = layer->GetView(eye).PostMultiply(layer->GetModelTransform(eye)); + matrix.PostMultiplyInPlace(scale); + ovrMatrix4f modelView = ovrMatrixFrom(matrix); + + device::EyeRect textureRect = layer->GetTextureRect(eye); + + ovrLayer.Textures[i].ColorSwapChain = GetTargetSwapChain(aClearSwapChain); + ovrLayer.Textures[i].SwapChainIndex = 0; + ovrLayer.Textures[i].TexCoordsFromTanAngles = ovrMatrix4f_TanAngleMatrixFromUnitSquare(&modelView); + ovrLayer.Textures[i].TextureRect.x = textureRect.mX; + ovrLayer.Textures[i].TextureRect.y = textureRect.mY; + ovrLayer.Textures[i].TextureRect.width = textureRect.mWidth; + ovrLayer.Textures[i].TextureRect.height = textureRect.mHeight; + clip = clip || !textureRect.IsDefault(); + } + SetClipEnabled(clip); + + ovrLayer.HeadPose = aTracking.HeadPose; +} + +// OculusLayerCylinder + +OculusLayerCylinderPtr +OculusLayerCylinder::Create(const VRLayerCylinderPtr& aLayer, const OculusLayerPtr& aSource) { + auto result = std::make_shared(); + result->layer = aLayer; + if (aSource) { + result->TakeSurface(aSource); + } + return result; +} + +void +OculusLayerCylinder::Init(JNIEnv * aEnv, vrb::RenderContextPtr& aContext) { + ovrLayer = vrapi_DefaultLayerCylinder2(); + OculusLayerSurface::Init(aEnv, aContext); +} + +void +OculusLayerCylinder::Update(const ovrTracking2& aTracking, ovrTextureSwapChain* aClearSwapChain) { + ovrLayer.HeadPose = aTracking.HeadPose; + ovrLayer.Header.SrcBlend = VRAPI_FRAME_LAYER_BLEND_ONE; + ovrLayer.Header.DstBlend = VRAPI_FRAME_LAYER_BLEND_ONE_MINUS_SRC_ALPHA; + + for ( int i = 0; i < VRAPI_FRAME_LAYER_EYE_MAX; i++ ) { + device::Eye eye = i == 0 ? device::Eye::Left : device::Eye::Right; + vrb::Matrix modelView = layer->GetView(eye).PostMultiply(layer->GetModelTransform(eye)); + ovrMatrix4f matrix = ovrMatrixFrom(modelView); + ovrLayer.Textures[i].TexCoordsFromTanAngles = ovrMatrix4f_Inverse(&matrix); + ovrLayer.Textures[i].ColorSwapChain = GetTargetSwapChain(aClearSwapChain); + ovrLayer.Textures[i].SwapChainIndex = 0; + + const vrb::Vector scale = layer->GetUVTransform(eye).GetScale(); + const vrb::Vector translation = layer->GetUVTransform(eye).GetTranslation(); + + ovrLayer.Textures[i].TextureMatrix.M[0][0] = scale.x(); + ovrLayer.Textures[i].TextureMatrix.M[1][1] = scale.y(); + ovrLayer.Textures[i].TextureMatrix.M[0][2] = translation.x(); + ovrLayer.Textures[i].TextureMatrix.M[1][2] = translation.y(); + + ovrLayer.Textures[i].TextureRect.width = 1.0f; + ovrLayer.Textures[i].TextureRect.height = 1.0f; + } +} + + +// OculusLayerCube + +OculusLayerCubePtr +OculusLayerCube::Create(const VRLayerCubePtr& aLayer, GLint aInternalFormat) { + auto result = std::make_shared(); + result->layer = aLayer; + result->glFormat = aInternalFormat; + return result; +} + +void +OculusLayerCube::Init(JNIEnv * aEnv, vrb::RenderContextPtr& aContext) { + if (swapChain) { + return; + } + + ovrLayer = vrapi_DefaultLayerCube2(); + ovrLayer.Offset.x = 0.0f; + ovrLayer.Offset.y = 0.0f; + ovrLayer.Offset.z = 0.0f; + swapChain = vrapi_CreateTextureSwapChain3(VRAPI_TEXTURE_TYPE_CUBE, glFormat, layer->GetWidth(), layer->GetHeight(), 1, 1); + layer->SetTextureHandle(vrapi_GetTextureSwapChainHandle(swapChain, 0)); + OculusLayerBase::Init(aEnv, aContext); +} + +void +OculusLayerCube::Destroy() { + if (swapChain == nullptr) { + return; + } + layer->SetTextureHandle(0); + layer->SetLoaded(false); + OculusLayerBase::Destroy(); +} + +bool +OculusLayerCube::IsLoaded() const { + return layer->IsLoaded(); +} + +void +OculusLayerCube::Update(const ovrTracking2& aTracking, ovrTextureSwapChain* aClearSwapChain) { + OculusLayerBase::Update(aTracking, aClearSwapChain); + const ovrMatrix4f centerEyeViewMatrix = vrapi_GetViewMatrixFromPose(&aTracking.HeadPose.Pose); + const ovrMatrix4f cubeMatrix = ovrMatrix4f_TanAngleMatrixForCubeMap(¢erEyeViewMatrix); + ovrLayer.HeadPose = aTracking.HeadPose; + ovrLayer.TexCoordsFromTanAngles = cubeMatrix; + + for (int i = 0; i < VRAPI_FRAME_LAYER_EYE_MAX; ++i) { + ovrLayer.Textures[i].ColorSwapChain = GetTargetSwapChain(aClearSwapChain); + ovrLayer.Textures[i].SwapChainIndex = 0; + } +} + +// OculusLayerEquirect; + +OculusLayerEquirectPtr +OculusLayerEquirect::Create(const VRLayerEquirectPtr& aLayer, const OculusLayerPtr& aSourceLayer) { + auto result = std::make_shared(); + result->layer = aLayer; + result->sourceLayer = aSourceLayer; + return result; +} + +void +OculusLayerEquirect::Init(JNIEnv * aEnv, vrb::RenderContextPtr& aContext) { + OculusLayerPtr source = sourceLayer.lock(); + if (!source) { + return; + } + + swapChain = source->GetSwapChain(); + ovrLayer = vrapi_DefaultLayerEquirect2(); + ovrLayer.HeadPose.Pose.Position.x = 0.0f; + ovrLayer.HeadPose.Pose.Position.y = 0.0f; + ovrLayer.HeadPose.Pose.Position.z = 0.0f; + ovrLayer.HeadPose.Pose.Orientation.x = 0.0f; + ovrLayer.HeadPose.Pose.Orientation.y = 0.0f; + ovrLayer.HeadPose.Pose.Orientation.z = 0.0f; + ovrLayer.HeadPose.Pose.Orientation.w = 1.0f; + ovrLayer.TexCoordsFromTanAngles = ovrMatrix4f_CreateIdentity(); + OculusLayerBase::Init(aEnv, aContext); +} + +void +OculusLayerEquirect::Destroy() { + swapChain = nullptr; + OculusLayerBase::Destroy(); +} + +bool +OculusLayerEquirect::IsDrawRequested() const { + OculusLayerPtr source = sourceLayer.lock(); + return source && source->GetSwapChain() && source->IsComposited() && layer->IsDrawRequested(); +} + +void +OculusLayerEquirect::Update(const ovrTracking2& aTracking, ovrTextureSwapChain* aClearSwapChain) { + OculusLayerPtr source = sourceLayer.lock(); + if (source) { + swapChain = source->GetSwapChain(); + } + OculusLayerBase::Update(aTracking, aClearSwapChain); + + vrb::Quaternion q(layer->GetModelTransform(device::Eye::Left)); + ovrLayer.HeadPose.Pose.Orientation.x = q.x(); + ovrLayer.HeadPose.Pose.Orientation.y = q.y(); + ovrLayer.HeadPose.Pose.Orientation.z = q.z(); + ovrLayer.HeadPose.Pose.Orientation.w = q.w(); + + bool clip = false; + for (int i = 0; i < VRAPI_FRAME_LAYER_EYE_MAX; ++i) { + const device::Eye eye = i == 0 ? device::Eye::Left : device::Eye::Right; + ovrLayer.Textures[i].ColorSwapChain = GetTargetSwapChain(aClearSwapChain); + ovrLayer.Textures[i].SwapChainIndex = 0; + const vrb::Vector scale = layer->GetUVTransform(eye).GetScale(); + const vrb::Vector translation = layer->GetUVTransform(eye).GetTranslation(); + + ovrLayer.Textures[i].TextureMatrix.M[0][0] = scale.x(); + ovrLayer.Textures[i].TextureMatrix.M[1][1] = scale.y(); + ovrLayer.Textures[i].TextureMatrix.M[0][2] = translation.x(); + ovrLayer.Textures[i].TextureMatrix.M[1][2] = translation.y(); + + device::EyeRect textureRect = layer->GetTextureRect(eye); + ovrLayer.Textures[i].TextureRect.x = textureRect.mX; + ovrLayer.Textures[i].TextureRect.y = textureRect.mY; + ovrLayer.Textures[i].TextureRect.width = textureRect.mWidth; + ovrLayer.Textures[i].TextureRect.height = textureRect.mHeight; + clip = clip || !textureRect.IsDefault(); + } + SetClipEnabled(clip); +} + + +} diff --git a/app/src/oculusvr/cpp/OculusVRLayers.h b/app/src/oculusvr/cpp/OculusVRLayers.h new file mode 100644 index 000000000..59495b7c3 --- /dev/null +++ b/app/src/oculusvr/cpp/OculusVRLayers.h @@ -0,0 +1,360 @@ +#pragma once + +#include "vrb/Forward.h" +#include "vrb/MacroUtils.h" +#include "vrb/FBO.h" +#include "vrb/Color.h" +#include "vrb/Matrix.h" +#include "vrb/GLError.h" +#include "DeviceDelegate.h" +#include "VRLayer.h" +#include "VrApi.h" +#include "VrApi_Helpers.h" +#include "VrApi_SystemUtils.h" +#include + +namespace crow { + +class OculusLayer; + +typedef std::shared_ptr OculusLayerPtr; + +struct SurfaceChangedTarget { + OculusLayer *layer; + + SurfaceChangedTarget(OculusLayer *aLayer) : layer(aLayer) {}; +}; + +typedef std::shared_ptr SurfaceChangedTargetPtr; +typedef std::weak_ptr SurfaceChangedTargetWeakPtr; + +class OculusLayer { +public: + virtual void Init(JNIEnv *aEnv, vrb::RenderContextPtr &aContext) = 0; + virtual void Update(const ovrTracking2 &aTracking, ovrTextureSwapChain *aClearSwapChain) = 0; + virtual ovrTextureSwapChain *GetSwapChain() const = 0; + virtual const ovrLayerHeader2 *Header() const = 0; + virtual void SetCurrentEye(device::Eye aEye) = 0; + virtual bool IsDrawRequested() const = 0; + virtual bool GetDrawInFront() const = 0; + virtual void ClearRequestDraw() = 0; + virtual bool IsComposited() const = 0; + virtual void SetComposited(bool aValue) = 0; + virtual VRLayerPtr GetLayer() const = 0; + virtual void Destroy() = 0; + typedef std::function BindDelegate; + virtual void SetBindDelegate(const BindDelegate &aDelegate) = 0; + virtual jobject GetSurface() const = 0; + virtual SurfaceChangedTargetPtr GetSurfaceChangedTarget() const = 0; + + virtual void + HandleResize(ovrTextureSwapChain *newSwapChain, jobject newSurface, vrb::FBOPtr newFBO) = 0; + + virtual ~OculusLayer() {} +}; + +template +class OculusLayerBase : public OculusLayer { +public: + ovrTextureSwapChain *swapChain = nullptr; + SurfaceChangedTargetPtr surfaceChangedTarget; + T layer; + U ovrLayer; + + void Init(JNIEnv *aEnv, vrb::RenderContextPtr &aContext) override { + layer->SetInitialized(true); + surfaceChangedTarget = std::make_shared(this); + SurfaceChangedTargetWeakPtr weakTarget = surfaceChangedTarget; + layer->NotifySurfaceChanged(VRLayer::SurfaceChange::Create, [=]() { + SurfaceChangedTargetPtr target = weakTarget.lock(); + if (target) { + target->layer->SetComposited(true); + } + }); + } + + virtual void + Update(const ovrTracking2 &aTracking, ovrTextureSwapChain *aClearSwapChain) override { + vrb::Color tintColor = layer->GetTintColor(); + if (!IsComposited() && layer->GetClearColor().Alpha()) { + tintColor = layer->GetClearColor(); + } + ovrLayer.Header.ColorScale.x = tintColor.Red(); + ovrLayer.Header.ColorScale.y = tintColor.Green(); + ovrLayer.Header.ColorScale.z = tintColor.Blue(); + ovrLayer.Header.ColorScale.w = tintColor.Alpha(); + } + + virtual ovrTextureSwapChain *GetSwapChain() const override { + return swapChain; + } + + const ovrLayerHeader2 *Header() const override { + return &ovrLayer.Header; + } + + void SetCurrentEye(device::Eye aEye) override { + layer->SetCurrentEye(aEye); + } + + virtual bool IsDrawRequested() const override { + return layer->IsDrawRequested() && + ((swapChain && IsComposited()) || layer->GetClearColor().Alpha() > 0.0f); + } + + bool GetDrawInFront() const override { + return layer->GetDrawInFront(); + } + + void ClearRequestDraw() override { + layer->ClearRequestDraw(); + } + + bool IsComposited() const override { + return layer->IsComposited(); + } + + void SetComposited(bool aValue) override { + layer->SetComposited(aValue); + } + + VRLayerPtr GetLayer() const override { + return layer; + } + + void SetClipEnabled(bool aEnabled) { + if (aEnabled) { + ovrLayer.Header.Flags |= VRAPI_FRAME_LAYER_FLAG_CLIP_TO_TEXTURE_RECT; + } else { + ovrLayer.Header.Flags &= ~VRAPI_FRAME_LAYER_FLAG_CLIP_TO_TEXTURE_RECT; + } + } + + void Destroy() override { + if (swapChain != nullptr) { + vrapi_DestroyTextureSwapChain(swapChain); + swapChain = nullptr; + } + layer->SetInitialized(false); + SetComposited(false); + layer->NotifySurfaceChanged(VRLayer::SurfaceChange::Destroy, nullptr); + } + + void SetBindDelegate(const BindDelegate &aDelegate) override {} + + jobject GetSurface() const override { + return nullptr; + } + + SurfaceChangedTargetPtr GetSurfaceChangedTarget() const override { + return surfaceChangedTarget; + } + + void HandleResize(ovrTextureSwapChain *newSwapChain, jobject newSurface, + vrb::FBOPtr newFBO) override {} + + ovrTextureSwapChain *GetTargetSwapChain(ovrTextureSwapChain *aClearSwapChain) { + return (IsComposited() || layer->GetClearColor().Alpha() == 0) ? swapChain : aClearSwapChain; + } + + virtual ~OculusLayerBase() {} +}; + + +template +class OculusLayerSurface : public OculusLayerBase { +public: + jobject surface = nullptr; + vrb::FBOPtr fbo; + vrb::RenderContextWeak contextWeak; + JNIEnv *jniEnv = nullptr; + OculusLayer::BindDelegate bindDelegate; + + void Init(JNIEnv *aEnv, vrb::RenderContextPtr &aContext) override { + this->jniEnv = aEnv; + this->contextWeak = aContext; + this->ovrLayer.Header.SrcBlend = VRAPI_FRAME_LAYER_BLEND_ONE; + this->ovrLayer.Header.DstBlend = VRAPI_FRAME_LAYER_BLEND_ONE_MINUS_SRC_ALPHA; + if (this->swapChain) { + return; + } + + InitSwapChain(this->swapChain, this->surface, this->fbo); + this->layer->SetResizeDelegate([=] { + Resize(); + }); + OculusLayerBase::Init(aEnv, aContext); + } + + void Resize() { + if (!this->swapChain) { + return; + } + // Delay the destruction of the current swapChain until the new one is composited. + // This is required to prevent a black flicker when resizing. + ovrTextureSwapChain *newSwapChain = nullptr; + jobject newSurface = nullptr; + vrb::FBOPtr newFBO; + InitSwapChain(newSwapChain, newSurface, newFBO); + this->layer->SetSurface(newSurface); + + SurfaceChangedTargetWeakPtr weakTarget = this->surfaceChangedTarget; + this->layer->NotifySurfaceChanged(VRLayer::SurfaceChange::Create, [=]() { + SurfaceChangedTargetPtr target = weakTarget.lock(); + if (target && target->layer) { + target->layer->HandleResize(newSwapChain, newSurface, newFBO); + } + }); + } + + void + HandleResize(ovrTextureSwapChain *newSwapChain, jobject newSurface, vrb::FBOPtr newFBO) override { + if (this->surface) { + jniEnv->DeleteGlobalRef(this->surface); + } + if (this->swapChain) { + vrapi_DestroyTextureSwapChain(this->swapChain); + } + this->swapChain = newSwapChain; + this->surface = newSurface; + this->fbo = newFBO; + this->SetComposited(true); + } + + void Destroy() override { + this->fbo = nullptr; + if (this->surface) { + this->jniEnv->DeleteGlobalRef(surface); + this->surface = nullptr; + this->layer->SetSurface(nullptr); + } + OculusLayerBase::Destroy(); + } + + void SetBindDelegate(const OculusLayer::BindDelegate &aDelegate) override { + bindDelegate = aDelegate; + this->layer->SetBindDelegate([=](GLenum aTarget, bool aBind) { + if (bindDelegate) { + bindDelegate(this->fbo, aTarget, aBind); + } + }); + } + + virtual jobject GetSurface() const override { + return surface; + } + +protected: + void TakeSurface(const OculusLayerPtr &aSource) { + this->swapChain = aSource->GetSwapChain(); + this->surface = aSource->GetSurface(); + this->surfaceChangedTarget = aSource->GetSurfaceChangedTarget(); + if (this->surfaceChangedTarget) { + // Indicate that the first composite notification should be notified to this layer. + this->surfaceChangedTarget->layer = this; + } + this->SetComposited(aSource->IsComposited()); + this->layer->SetInitialized(aSource->GetLayer()->IsInitialized()); + this->layer->SetResizeDelegate([=] { + Resize(); + }); + } + +private: + void InitSwapChain(ovrTextureSwapChain *&swapChainOut, jobject &surfaceOut, vrb::FBOPtr &fboOut) { + if (this->layer->GetSurfaceType() == VRLayerQuad::SurfaceType::AndroidSurface) { + swapChainOut = vrapi_CreateAndroidSurfaceSwapChain(this->layer->GetWidth(), + this->layer->GetHeight()); + surfaceOut = vrapi_GetTextureSwapChainAndroidSurface(swapChainOut); + surfaceOut = this->jniEnv->NewGlobalRef(surfaceOut); + this->layer->SetSurface(surface); + } else { + swapChainOut = vrapi_CreateTextureSwapChain(VRAPI_TEXTURE_TYPE_2D, VRAPI_TEXTURE_FORMAT_8888, + this->layer->GetWidth(), this->layer->GetHeight(), + 1, false); + vrb::RenderContextPtr ctx = this->contextWeak.lock(); + fboOut = vrb::FBO::Create(ctx); + GLuint texture = vrapi_GetTextureSwapChainHandle(swapChainOut, 0); + VRB_GL_CHECK(glBindTexture(GL_TEXTURE_2D, texture)); + VRB_GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); + VRB_GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); + VRB_GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); + VRB_GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); + vrb::FBO::Attributes attributes; + attributes.depth = false; + attributes.samples = 0; + VRB_GL_CHECK( + fboOut->SetTextureHandle(texture, this->layer->GetWidth(), this->layer->GetHeight(), + attributes)); + if (fboOut->IsValid()) { + fboOut->Bind(); + VRB_GL_CHECK(glClearColor(0.0f, 0.0f, 0.0f, 0.0f)); + VRB_GL_CHECK(glClear(GL_COLOR_BUFFER_BIT)); + fboOut->Unbind(); + } else { + VRB_WARN("FAILED to make valid FBO for OculusLayerSurface"); + } + } + } + +}; + +class OculusLayerQuad; + +typedef std::shared_ptr OculusLayerQuadPtr; + +class OculusLayerQuad : public OculusLayerSurface { +public: + static OculusLayerQuadPtr + Create(const VRLayerQuadPtr &aLayer, const OculusLayerPtr &aSource = nullptr); + void Init(JNIEnv *aEnv, vrb::RenderContextPtr &aContext) override; + void Update(const ovrTracking2 &aTracking, ovrTextureSwapChain *aClearSwapChain) override; +}; + + +class OculusLayerCylinder; + +typedef std::shared_ptr OculusLayerCylinderPtr; + +class OculusLayerCylinder : public OculusLayerSurface { +public: + static OculusLayerCylinderPtr + Create(const VRLayerCylinderPtr &aLayer, const OculusLayerPtr &aSource = nullptr); + void Init(JNIEnv *aEnv, vrb::RenderContextPtr &aContext) override; + void Update(const ovrTracking2 &aTracking, ovrTextureSwapChain *aClearSwapChain) override; +}; + + +class OculusLayerCube; + +typedef std::shared_ptr OculusLayerCubePtr; + +class OculusLayerCube : public OculusLayerBase { +public: + static OculusLayerCubePtr Create(const VRLayerCubePtr &aLayer, GLint aInternalFormat); + void Init(JNIEnv *aEnv, vrb::RenderContextPtr &aContext) override; + void Update(const ovrTracking2 &aTracking, ovrTextureSwapChain *aClearSwapChain) override; + void Destroy() override; + bool IsLoaded() const; + +protected: + GLint glFormat; +}; + +class OculusLayerEquirect; + +typedef std::shared_ptr OculusLayerEquirectPtr; + +class OculusLayerEquirect : public OculusLayerBase { +public: + std::weak_ptr sourceLayer; + + static OculusLayerEquirectPtr + Create(const VRLayerEquirectPtr &aLayer, const OculusLayerPtr &aSourceLayer); + void Init(JNIEnv *aEnv, vrb::RenderContextPtr &aContext) override; + void Update(const ovrTracking2 &aTracking, ovrTextureSwapChain *aClearSwapChain) override; + void Destroy() override; + bool IsDrawRequested() const override; +}; + +}