From 945e1db49045fffab64b712d863e9866b29c0f7a Mon Sep 17 00:00:00 2001 From: Imanol Fernandez Date: Wed, 28 Aug 2019 17:47:22 +0200 Subject: [PATCH] Add support for clearing window color before GV does the first composition --- .../vrbrowser/ui/widgets/UIWidget.java | 4 +- .../vrbrowser/ui/widgets/WidgetPlacement.java | 6 +- .../vrbrowser/ui/widgets/WindowWidget.java | 14 +++- app/src/main/cpp/BrowserWorld.cpp | 4 +- app/src/main/cpp/Quad.cpp | 8 ++ app/src/main/cpp/Quad.h | 1 + app/src/main/cpp/VRLayer.cpp | 16 +++- app/src/main/cpp/VRLayer.h | 2 + app/src/main/cpp/Widget.cpp | 63 +++++++++------ app/src/main/cpp/Widget.h | 4 +- app/src/main/cpp/WidgetBorder.cpp | 22 +----- app/src/main/cpp/WidgetPlacement.cpp | 8 +- app/src/main/cpp/WidgetPlacement.h | 5 +- app/src/main/cpp/shaders/clear_color.fs | 16 ++++ app/src/main/cpp/vrb | 2 +- app/src/main/res/values/colors.xml | 2 + .../oculusvr/cpp/DeviceDelegateOculusVR.cpp | 79 ++++++++++++++----- 17 files changed, 181 insertions(+), 75 deletions(-) create mode 100644 app/src/main/cpp/shaders/clear_color.fs diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/UIWidget.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/UIWidget.java index b44207933..ef6de0d5a 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/UIWidget.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/UIWidget.java @@ -208,12 +208,12 @@ public boolean isDialog() { @Override public void setFirstDraw(final boolean aIsFirstDraw) { - mWidgetPlacement.firstDraw = aIsFirstDraw; + mWidgetPlacement.composited = aIsFirstDraw; } @Override public boolean getFirstDraw() { - return mWidgetPlacement.firstDraw; + return mWidgetPlacement.composited; } @Override diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/WidgetPlacement.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/WidgetPlacement.java index 392499390..8572337c7 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/WidgetPlacement.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/WidgetPlacement.java @@ -44,13 +44,15 @@ public WidgetPlacement(Context aContext) { public boolean visible = true; public boolean opaque = false; public boolean showPointer = true; - public boolean firstDraw = false; + public boolean composited = false; public boolean layer = true; public boolean proxifyLayer = false; public float textureScale = 0.7f; // Widget will be curved if enabled. public boolean cylinder = true; public int borderColor = 0; + // Color used to render the widget before the it's composited + public int clearColor = 0; /* * Flat surface placements are automatically mapped to curved coordinates. * If a radius is set it's used for the automatic mapping of the yaw & angle when the @@ -85,7 +87,7 @@ public void copyFrom(WidgetPlacement w) { this.visible = w.visible; this.opaque = w.opaque; this.showPointer = w.showPointer; - this.firstDraw = w.firstDraw; + this.composited = w.composited; this.layer = w.layer; this.textureScale = w.textureScale; this.cylinder = w.cylinder; diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/WindowWidget.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/WindowWidget.java index eb207addf..92cea204f 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/WindowWidget.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/WindowWidget.java @@ -159,6 +159,11 @@ public WindowWidget(Context aContext, int windowId, boolean privateMode) { mHandle = ((WidgetManagerDelegate)aContext).newWidgetHandle(); mWidgetPlacement = new WidgetPlacement(aContext); initializeWidgetPlacement(mWidgetPlacement); + if (mSessionStack.isPrivateMode()) { + mWidgetPlacement.clearColor = ViewUtils.ARGBtoRGBA(getContext().getColor(R.color.window_private_clear_color)); + } else { + mWidgetPlacement.clearColor = ViewUtils.ARGBtoRGBA(getContext().getColor(R.color.window_blank_clear_color)); + } mTopBar = new TopBarWidget(aContext); mTopBar.attachToWindow(this); @@ -767,12 +772,12 @@ public void releaseWidget() { @Override public void setFirstDraw(final boolean aIsFirstDraw) { - mWidgetPlacement.firstDraw = aIsFirstDraw; + mWidgetPlacement.composited = aIsFirstDraw; } @Override public boolean getFirstDraw() { - return mWidgetPlacement.firstDraw; + return mWidgetPlacement.composited; } @Override @@ -1280,7 +1285,10 @@ public void onFirstComposite(GeckoSession session) { if (mFirstDrawCallback != null) { // Post this call because running it synchronously can cause a deadlock if the runnable // resizes the widget and calls surfaceChanged. See https://github.com/MozillaReality/FirefoxReality/issues/1459. - ThreadUtils.postToUiThread(mFirstDrawCallback); + // 1s delay has been added because firstComposite callback is received before a Gecko layer is actually rendered + // and that makes the window transparent for a while. Remove the 1s delay when GV is updated with a better callback. + final int delay = 1000; + ThreadUtils.postDelayedToUiThread(mFirstDrawCallback, delay); mFirstDrawCallback = null; } } diff --git a/app/src/main/cpp/BrowserWorld.cpp b/app/src/main/cpp/BrowserWorld.cpp index f1fe20d5d..e04b81fd4 100644 --- a/app/src/main/cpp/BrowserWorld.cpp +++ b/app/src/main/cpp/BrowserWorld.cpp @@ -854,7 +854,7 @@ BrowserWorld::AddWidget(int32_t aHandle, const WidgetPlacementPtr& aPlacement) { if (aPlacement->cylinder && m.cylinderDensity > 0) { VRLayerCylinderPtr layer = m.device->CreateLayerCylinder(textureWidth, textureHeight, VRLayerQuad::SurfaceType::AndroidSurface); CylinderPtr cylinder = Cylinder::Create(m.create, layer); - widget = Widget::Create(m.context, aHandle, textureWidth, textureHeight, (int32_t)worldWidth, (int32_t)worldHeight, cylinder); + widget = Widget::Create(m.context, aHandle, aPlacement, textureWidth, textureHeight, (int32_t)worldWidth, (int32_t)worldHeight, cylinder); } if (!widget) { @@ -864,7 +864,7 @@ BrowserWorld::AddWidget(int32_t aHandle, const WidgetPlacementPtr& aPlacement) { } QuadPtr quad = Quad::Create(m.create, worldWidth, worldHeight, layer); - widget = Widget::Create(m.context, aHandle, textureWidth, textureHeight, quad); + widget = Widget::Create(m.context, aHandle, aPlacement, textureWidth, textureHeight, quad); } if (aPlacement->opaque) { diff --git a/app/src/main/cpp/Quad.cpp b/app/src/main/cpp/Quad.cpp index a6eb09e6b..ba5073409 100644 --- a/app/src/main/cpp/Quad.cpp +++ b/app/src/main/cpp/Quad.cpp @@ -335,6 +335,14 @@ Quad::GetWorldHeight() const { return m.GetWorldHeight(); } +vrb::RenderStatePtr +Quad::GetRenderState() const { + if (m.geometry) { + return m.geometry->GetRenderState(); + } + return nullptr; +} + void Quad::GetWorldSize(float& aWidth, float& aHeight) const { aWidth = m.worldMax.x() - m.worldMin.x(); diff --git a/app/src/main/cpp/Quad.h b/app/src/main/cpp/Quad.h index a8cebf5b1..41383f7a3 100644 --- a/app/src/main/cpp/Quad.h +++ b/app/src/main/cpp/Quad.h @@ -48,6 +48,7 @@ class Quad { const vrb::Vector& GetWorldMax() const; float GetWorldWidth() const; float GetWorldHeight() const; + vrb::RenderStatePtr GetRenderState() const; void GetWorldSize(float& aWidth, float& aHeight) const; void SetWorldSize(const float aWidth, const float aHeight) const; void SetWorldSize(const vrb::Vector& aMin, const vrb::Vector& aMax) const; diff --git a/app/src/main/cpp/VRLayer.cpp b/app/src/main/cpp/VRLayer.cpp index 0d4f6d6bf..d3a266fb1 100644 --- a/app/src/main/cpp/VRLayer.cpp +++ b/app/src/main/cpp/VRLayer.cpp @@ -22,6 +22,7 @@ struct VRLayer::State { vrb::Matrix modelTransform[2]; vrb::Matrix modelView[2]; device::Eye currentEye; + vrb::Color clearColor; vrb::Color tintColor; device::EyeRect textureRect[2]; SurfaceChangedDelegate surfaceChangedDelegate; @@ -33,6 +34,7 @@ struct VRLayer::State { drawRequested(false), drawInFront(false), currentEye(device::Eye::Left), + clearColor(0), tintColor(1.0f, 1.0f, 1.0f, 1.0f) { for (int i = 0; i < 2; ++i) { @@ -79,6 +81,12 @@ VRLayer::GetPriority() const { return m.priority; } + +const vrb::Color& +VRLayer::GetClearColor() const { + return m.clearColor; +} + const vrb::Color& VRLayer::GetTintColor() const { return m.tintColor; @@ -153,8 +161,14 @@ VRLayer::VRLayer(State& aState, LayerType aLayerType): m(aState) { m.layerType = aLayerType; } + +void +VRLayer::SetClearColor(const vrb::Color& aClearColor) { + m.clearColor = aClearColor; +} + void -VRLayer::SetTintColor(const vrb::Color &aTintColor) { +VRLayer::SetTintColor(const vrb::Color& aTintColor) { m.tintColor = aTintColor; } diff --git a/app/src/main/cpp/VRLayer.h b/app/src/main/cpp/VRLayer.h index 0f4ed1e0a..1bb1928d9 100644 --- a/app/src/main/cpp/VRLayer.h +++ b/app/src/main/cpp/VRLayer.h @@ -44,6 +44,7 @@ class VRLayer { const vrb::Matrix& GetView(device::Eye aEye) const; device::Eye GetCurrentEye() const; int32_t GetPriority() const; + const vrb::Color& GetClearColor() const; const vrb::Color& GetTintColor() const; const device::EyeRect& GetTextureRect(device::Eye aEye) const; bool GetDrawInFront() const; @@ -56,6 +57,7 @@ class VRLayer { void SetView(device::Eye aEye, const vrb::Matrix& aModelView); void SetCurrentEye(device::Eye aEye); void SetPriority(int32_t aPriority); + void SetClearColor(const vrb::Color& aClearColor); void SetTintColor(const vrb::Color& aTintColor); void SetTextureRect(device::Eye aEye, const device::EyeRect& aTextureRect); void SetSurfaceChangedDelegate(const SurfaceChangedDelegate& aDelegate); diff --git a/app/src/main/cpp/Widget.cpp b/app/src/main/cpp/Widget.cpp index 5b1f666e2..18f6576f4 100644 --- a/app/src/main/cpp/Widget.cpp +++ b/app/src/main/cpp/Widget.cpp @@ -23,6 +23,7 @@ #include "vrb/RenderState.h" #include "vrb/SurfaceTextureFactory.h" #include "vrb/TextureSurface.h" +#include "vrb/TextureCache.h" #include "vrb/Toggle.h" #include "vrb/Transform.h" #include "vrb/Vector.h" @@ -66,7 +67,7 @@ struct Widget::State { , cylinderDensity(4680.0f) {} - void Initialize(const int aHandle, const int32_t aTextureWidth, const int32_t aTextureHeight, + void Initialize(const int aHandle, const WidgetPlacementPtr& aPlacement, const int32_t aTextureWidth, const int32_t aTextureHeight, const QuadPtr& aQuad, const CylinderPtr& aCylinder) { handle = (uint32_t)aHandle; name = "crow::Widget-" + std::to_string(handle); @@ -74,7 +75,7 @@ struct Widget::State { if (!render) { return; } - + placement = aPlacement; quad = aQuad; cylinder = aCylinder; @@ -92,12 +93,8 @@ struct Widget::State { transform->AddNode(cylinder->GetRoot()); } - if (GetLayer()) { - toggleState = true; - root->ToggleAll(true); - } else { - root->ToggleAll(false); - } + toggleState = IsReadyForComposition(); + root->ToggleAll(toggleState); } void UpdateSurface(const int32_t aTextureWidth, const int32_t aTextureHeight) { @@ -112,21 +109,32 @@ struct Widget::State { vrb::RenderContextPtr render = context.lock(); surface = vrb::TextureSurface::Create(render, name); } + + vrb::Color tintColor(1.0f, 1.0f, 1.0f, 1.0f); + std::string customFragment; + if (!placement->composited && placement->GetClearColor().Alpha() > 0.0f) { + customFragment = +#include "shaders/clear_color.fs" + ; + tintColor = placement->GetClearColor(); + } + if (quad) { quad->SetTexture(surface, aTextureWidth, aTextureHeight); quad->SetMaterial(vrb::Color(0.4f, 0.4f, 0.4f), vrb::Color(1.0f, 1.0f, 1.0f), vrb::Color(0.0f, 0.0f, 0.0f), 0.0f); + quad->GetRenderState()->SetCustomFragmentShader(customFragment); + quad->GetRenderState()->SetTintColor(tintColor); } else if (cylinder) { cylinder->SetTexture(surface, aTextureWidth, aTextureHeight); cylinder->SetMaterial(vrb::Color(0.4f, 0.4f, 0.4f), vrb::Color(1.0f, 1.0f, 1.0f), vrb::Color(0.0f, 0.0f, 0.0f), 0.0f); + cylinder->GetRenderState()->SetCustomFragmentShader(customFragment); + cylinder->GetRenderState()->SetTintColor(tintColor); } } } - bool FirstDraw() { - if (!placement) { - return false; - } - return placement->firstDraw; + bool IsReadyForComposition() { + return GetLayer() || placement->composited || placement->GetClearColor().Alpha() > 0; } const VRLayerSurfacePtr GetLayer() { @@ -198,21 +206,21 @@ struct Widget::State { }; WidgetPtr -Widget::Create(vrb::RenderContextPtr& aContext, const int aHandle, +Widget::Create(vrb::RenderContextPtr& aContext, const int aHandle, const WidgetPlacementPtr& aPlacement, const int32_t aTextureWidth, const int32_t aTextureHeight,const QuadPtr& aQuad) { WidgetPtr result = std::make_shared >(aContext); aQuad->GetWorldMinAndMax(result->m.min, result->m.max); - result->m.Initialize(aHandle, aTextureWidth, aTextureHeight, aQuad, nullptr); + result->m.Initialize(aHandle, aPlacement, aTextureWidth, aTextureHeight, aQuad, nullptr); return result; } WidgetPtr -Widget::Create(vrb::RenderContextPtr& aContext, const int aHandle, const float aWorldWidth, const float aWorldHeight, +Widget::Create(vrb::RenderContextPtr& aContext, const int aHandle, const WidgetPlacementPtr& aPlacement, const float aWorldWidth, const float aWorldHeight, const int32_t aTextureWidth, const int32_t aTextureHeight, const CylinderPtr& aCylinder) { WidgetPtr result = std::make_shared >(aContext); result->m.min = vrb::Vector(-aWorldWidth * 0.5f, -aWorldHeight * 0.5f, 0.0f); - result->m.max = vrb::Vector(aWorldWidth * 0.5f, aWorldHeight * 0.5f, 0.0f); - result->m.Initialize(aHandle, aTextureWidth, aTextureHeight, nullptr, aCylinder); + result->m.max = vrb::Vector(aWorldWidth *0.5f, aWorldHeight * 0.5f, 0.0f); + result->m.Initialize(aHandle, aPlacement, aTextureWidth, aTextureHeight, nullptr, aCylinder); return result; } @@ -224,7 +232,7 @@ Widget::GetHandle() const { void Widget::ResetFirstDraw() { if (m.placement) { - m.placement->firstDraw = false; + m.placement->composited = false; } if (m.root) { m.root->ToggleAll(false); @@ -352,7 +360,7 @@ Widget::SetTransform(const vrb::Matrix& aTransform) { void Widget::ToggleWidget(const bool aEnabled) { m.toggleState = aEnabled; - m.root->ToggleAll(aEnabled && m.FirstDraw()); + m.root->ToggleAll(aEnabled && m.IsReadyForComposition()); } bool @@ -434,13 +442,22 @@ Widget::GetPlacement() const { void Widget::SetPlacement(const WidgetPlacementPtr& aPlacement) { - if (!m.FirstDraw() && aPlacement && aPlacement->firstDraw && m.root) { - m.root->ToggleAll(m.toggleState); - } + bool wasComposited = m.placement->composited; m.placement = aPlacement; + if (!wasComposited && aPlacement->composited && m.root) { + m.root->ToggleAll(m.toggleState); + int32_t textureWidth, textureHeight; + GetSurfaceTextureSize(textureWidth, textureHeight); + m.UpdateSurface(textureWidth, textureHeight); + } if (m.cylinder) { m.UpdateCylinderMatrix(); } + + VRLayerSurfacePtr layer = GetLayer(); + if (layer) { + layer->SetClearColor(aPlacement->clearColor); + } } void diff --git a/app/src/main/cpp/Widget.h b/app/src/main/cpp/Widget.h index 3b77815db..f6da74488 100644 --- a/app/src/main/cpp/Widget.h +++ b/app/src/main/cpp/Widget.h @@ -35,9 +35,9 @@ typedef std::shared_ptr WidgetPlacementPtr; class Widget { public: - static WidgetPtr Create(vrb::RenderContextPtr& aContext, const int aHandle, + static WidgetPtr Create(vrb::RenderContextPtr& aContext, const int aHandle, const WidgetPlacementPtr& aPlacement, const int32_t aTextureWidth, const int32_t aTextureHeight, const QuadPtr& aQuad); - static WidgetPtr Create(vrb::RenderContextPtr& aContext, const int aHandle, const float aWorldWidth, const float aWorldHeight, + static WidgetPtr Create(vrb::RenderContextPtr& aContext, const int aHandle, const WidgetPlacementPtr& aPlacement, const float aWorldWidth, const float aWorldHeight, const int32_t aTextureWidth, const int32_t aTextureHeight, const CylinderPtr& aCylinder); uint32_t GetHandle() const; void ResetFirstDraw(); diff --git a/app/src/main/cpp/WidgetBorder.cpp b/app/src/main/cpp/WidgetBorder.cpp index 33556dea7..14fd2f38f 100644 --- a/app/src/main/cpp/WidgetBorder.cpp +++ b/app/src/main/cpp/WidgetBorder.cpp @@ -27,23 +27,6 @@ namespace crow { -static const char* sCylinderFragmentShader = R"SHADER( -precision highp float; - -uniform sampler2D u_texture0; -varying vec4 v_color; -varying vec2 v_uv; - -void main() { - vec4 color = vec4(1.0f, 1.0f, 1.0f, 1.0f); - if ((v_uv.x < 0.0f) || (v_uv.x > 1.0f)) { - color.a = 0.0f; - } - gl_FragColor = color * v_color; -} - -)SHADER"; - struct WidgetBorder::State { CylinderPtr cylinder; vrb::GeometryPtr geometry; @@ -156,7 +139,10 @@ WidgetBorderPtr WidgetBorder::Create(vrb::CreationContextPtr& aContext, const vr // Sometimes there is no handle to hide it (e.g. bottom bar and anchor points != 0.5f) vrb::TextureGLPtr defaultTexture = aContext->GetDefaultTexture(); result->m.cylinder->SetTexture(defaultTexture, defaultTexture->GetWidth(), defaultTexture->GetHeight()); - result->m.cylinder->GetRenderState()->SetCustomFragmentShader(sCylinderFragmentShader); + const std::string customFragment = +#include "shaders/clear_color.fs" + ; + result->m.cylinder->GetRenderState()->SetCustomFragmentShader(customFragment); result->m.transform->AddNode(result->m.cylinder->GetRoot()); } else { result->m.geometry = result->m.CreateGeometry(aContext, -max, max, aBorderRect); diff --git a/app/src/main/cpp/WidgetPlacement.cpp b/app/src/main/cpp/WidgetPlacement.cpp index 5556f1680..04fb5b9b2 100644 --- a/app/src/main/cpp/WidgetPlacement.cpp +++ b/app/src/main/cpp/WidgetPlacement.cpp @@ -53,13 +53,14 @@ WidgetPlacement::FromJava(JNIEnv* aEnv, jobject& aObject) { GET_BOOLEAN_FIELD(visible); GET_BOOLEAN_FIELD(opaque); GET_BOOLEAN_FIELD(showPointer); - GET_BOOLEAN_FIELD(firstDraw); + GET_BOOLEAN_FIELD(composited); GET_BOOLEAN_FIELD(layer); GET_BOOLEAN_FIELD(proxifyLayer); GET_FLOAT_FIELD(textureScale, "textureScale"); GET_BOOLEAN_FIELD(cylinder); GET_FLOAT_FIELD(cylinderMapRadius, "cylinderMapRadius"); GET_INT_FIELD(borderColor); + GET_INT_FIELD(clearColor); return result; } @@ -79,4 +80,9 @@ WidgetPlacement::GetTextureHeight() const { return (int32_t)ceilf(height * density * textureScale); } +vrb::Color +WidgetPlacement::GetClearColor() const { + return vrb::Color(clearColor); +} + } diff --git a/app/src/main/cpp/WidgetPlacement.h b/app/src/main/cpp/WidgetPlacement.h index 4cc4d23c6..44dcf21dc 100644 --- a/app/src/main/cpp/WidgetPlacement.h +++ b/app/src/main/cpp/WidgetPlacement.h @@ -6,6 +6,7 @@ #ifndef VRBROWSER_WIDGET_PLACEMENT_DOT_H #define VRBROWSER_WIDGET_PLACEMENT_DOT_H +#include "vrb/Color.h" #include "vrb/Vector.h" #include "vrb/MacroUtils.h" #include @@ -29,16 +30,18 @@ struct WidgetPlacement { bool visible; bool opaque; bool showPointer; - bool firstDraw; + bool composited; bool layer; bool proxifyLayer; float textureScale; bool cylinder; float cylinderMapRadius; int borderColor; + int clearColor; int32_t GetTextureWidth() const; int32_t GetTextureHeight() const; + vrb::Color GetClearColor() const; static const float kWorldDPIRatio; static WidgetPlacementPtr FromJava(JNIEnv* aEnv, jobject& aObject); diff --git a/app/src/main/cpp/shaders/clear_color.fs b/app/src/main/cpp/shaders/clear_color.fs new file mode 100644 index 000000000..0a5d27b5f --- /dev/null +++ b/app/src/main/cpp/shaders/clear_color.fs @@ -0,0 +1,16 @@ +R"SHADER( +precision VRB_FRAGMENT_PRECISION float; + +uniform sampler2D u_texture0; +varying vec4 v_color; +varying vec2 v_uv; + +void main() { + vec4 color = vec4(1.0f, 1.0f, 1.0f, 1.0f); + if ((v_uv.x < 0.0f) || (v_uv.x > 1.0f)) { + color.a = 0.0f; + } + gl_FragColor = color * v_color; +} + +)SHADER"; diff --git a/app/src/main/cpp/vrb b/app/src/main/cpp/vrb index db3c19d44..beeab7938 160000 --- a/app/src/main/cpp/vrb +++ b/app/src/main/cpp/vrb @@ -1 +1 @@ -Subproject commit db3c19d44adfb20f7303747f71ac55ef5ea6687c +Subproject commit beeab79380be87aadacd2e73efa8cbdd2e869846 diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index 2232c00c3..b082b63b5 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -42,4 +42,6 @@ #f5f6fa #1ac1dd #2bd2ee + #f4f4f4 + #331a50 diff --git a/app/src/oculusvr/cpp/DeviceDelegateOculusVR.cpp b/app/src/oculusvr/cpp/DeviceDelegateOculusVR.cpp index 3084b9e70..031c6d1d3 100644 --- a/app/src/oculusvr/cpp/DeviceDelegateOculusVR.cpp +++ b/app/src/oculusvr/cpp/DeviceDelegateOculusVR.cpp @@ -135,7 +135,7 @@ typedef std::weak_ptr SurfaceChangedTargetWeakPtr; class OculusLayer { public: virtual void Init(JNIEnv * aEnv, vrb::RenderContextPtr& aContext) = 0; - virtual void Update(const ovrTracking2& aTracking) = 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; @@ -175,8 +175,11 @@ class OculusLayerBase: public OculusLayer { }); } - virtual void Update(const ovrTracking2& aTracking) override{ + virtual void Update(const ovrTracking2& aTracking, ovrTextureSwapChain* aClearSwapChain) override{ vrb::Color tintColor = layer->GetTintColor(); + if (!composited && layer->GetClearColor().Alpha()) { + tintColor = layer->GetClearColor(); + } ovrLayer.Header.ColorScale.x = tintColor.Red(); ovrLayer.Header.ColorScale.y = tintColor.Green(); ovrLayer.Header.ColorScale.z = tintColor.Blue(); @@ -196,7 +199,7 @@ class OculusLayerBase: public OculusLayer { } virtual bool IsDrawRequested() const override { - return swapChain && composited && layer->IsDrawRequested(); + return layer->IsDrawRequested() && ((swapChain && composited) || layer->GetClearColor().Alpha() > 0.0f); } bool GetDrawInFront() const override { @@ -249,6 +252,10 @@ class OculusLayerBase: public OculusLayer { void HandleResize(ovrTextureSwapChain * newSwapChain, jobject newSurface, vrb::FBOPtr newFBO) override {} + ovrTextureSwapChain* GetTargetSwapChain(ovrTextureSwapChain* aClearSwapChain) { + return (composited || layer->GetClearColor().Alpha() == 0) ? swapChain : aClearSwapChain; + } + virtual ~OculusLayerBase() {} }; @@ -404,8 +411,8 @@ class OculusLayerQuad: public OculusLayerSurface::Init(aEnv, aContext); } - void Update(const ovrTracking2& aTracking) override { - OculusLayerSurface::Update(aTracking); + void Update(const ovrTracking2& aTracking, ovrTextureSwapChain* aClearSwapChain) override { + OculusLayerSurface::Update(aTracking, aClearSwapChain); const float w = layer->GetWorldWidth(); const float h = layer->GetWorldHeight(); @@ -422,7 +429,7 @@ class OculusLayerQuad: public OculusLayerSurfaceGetTextureRect(eye); - ovrLayer.Textures[i].ColorSwapChain = swapChain; + 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; @@ -456,8 +463,8 @@ class OculusLayerCylinder: public OculusLayerSurface::Init(aEnv, aContext); } - void Update(const ovrTracking2& aTracking) override { - OculusLayerSurface::Update(aTracking); + void Update(const ovrTracking2& aTracking, ovrTextureSwapChain* aClearSwapChain) override { + OculusLayerSurface::Update(aTracking, aClearSwapChain); const float w = layer->GetWorldWidth(); const float h = layer->GetWorldHeight(); @@ -470,7 +477,7 @@ class OculusLayerCylinder: public OculusLayerSurfaceGetView(eye).PostMultiply(layer->GetModelTransform(eye)); ovrMatrix4f matrix = ovrMatrixFrom(modelView); ovrLayer.Textures[i].TexCoordsFromTanAngles = ovrMatrix4f_Inverse(&matrix); - ovrLayer.Textures[i].ColorSwapChain = swapChain; + ovrLayer.Textures[i].ColorSwapChain = GetTargetSwapChain(aClearSwapChain); ovrLayer.Textures[i].SwapChainIndex = 0; const vrb::Vector scale = layer->GetUVTransform(eye).GetScale(); @@ -526,15 +533,15 @@ class OculusLayerCube: public OculusLayerBase { return layer->IsLoaded(); } - void Update(const ovrTracking2& aTracking) override { - OculusLayerBase::Update(aTracking); + 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 = swapChain; + ovrLayer.Textures[i].ColorSwapChain = GetTargetSwapChain(aClearSwapChain); ovrLayer.Textures[i].SwapChainIndex = 0; } } @@ -587,12 +594,12 @@ class OculusLayerEquirect: public OculusLayerBaseGetSwapChain() && source->IsComposited() && layer->IsDrawRequested(); } - void Update(const ovrTracking2& aTracking) override { + void Update(const ovrTracking2& aTracking, ovrTextureSwapChain* aClearSwapChain) override { OculusLayerPtr source = sourceLayer.lock(); if (source) { swapChain = source->GetSwapChain(); } - OculusLayerBase::Update(aTracking); + OculusLayerBase::Update(aTracking, aClearSwapChain); vrb::Quaternion q(layer->GetModelTransform(device::Eye::Left)); ovrLayer.HeadPose.Pose.Orientation.x = q.x(); @@ -603,7 +610,7 @@ class OculusLayerEquirect: public OculusLayerBaseGetUVTransform(eye).GetScale(); const vrb::Vector translation = layer->GetUVTransform(eye).GetTranslation(); @@ -660,6 +667,7 @@ struct DeviceDelegateOculusVR::State { OculusLayerCubePtr cubeLayer; OculusLayerEquirectPtr equirectLayer; std::vector uiLayers; + ovrTextureSwapChain* clearColorSwapChain = nullptr; device::RenderMode renderMode = device::RenderMode::StandAlone; vrb::FBOPtr currentFBO; vrb::FBOPtr previousFBO; @@ -1112,6 +1120,33 @@ struct DeviceDelegateOculusVR::State { aFBO->Bind(aTarget); currentFBO = aFBO; } + + ovrTextureSwapChain* CreateClearColorSwapChain(const float aWidth, const float aHeight) { + ovrTextureSwapChain* result = vrapi_CreateTextureSwapChain(VRAPI_TEXTURE_TYPE_2D, VRAPI_TEXTURE_FORMAT_8888, aWidth, aHeight, 1, false); + vrb::RenderContextPtr ctx = context.lock(); + vrb::FBOPtr fbo = vrb::FBO::Create(ctx); + GLuint texture = vrapi_GetTextureSwapChainHandle(result, 0); + VRB_GL_CHECK(glBindTexture(GL_TEXTURE_2D, texture)); + VRB_GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER_EXT)); + VRB_GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER_EXT)); + float border[] = { 0.0f, 0.0f, 0.0f, 0.0f }; + glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR_EXT, border); + 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(fbo->SetTextureHandle(texture, aWidth, aHeight, attributes)); + if (fbo->IsValid()) { + fbo->Bind(); + VRB_GL_CHECK(glClearColor(1.0f, 1.0f, 1.0f, 1.0f)); + VRB_GL_CHECK(glClear(GL_COLOR_BUFFER_BIT)); + fbo->Unbind(); + } else { + VRB_WARN("FAILED to make valid FBO for ClearColorSwapChain"); + } + return result; + } }; DeviceDelegateOculusVRPtr @@ -1436,13 +1471,13 @@ DeviceDelegateOculusVR::EndFrame(const bool aDiscard) { const ovrLayerHeader2* layers[ovrMaxLayerCount] = {}; if (m.cubeLayer && m.cubeLayer->IsLoaded() && m.cubeLayer->IsDrawRequested()) { - m.cubeLayer->Update(m.predictedTracking); + m.cubeLayer->Update(m.predictedTracking, m.clearColorSwapChain); layers[layerCount++] = m.cubeLayer->Header(); m.cubeLayer->ClearRequestDraw(); } if (m.equirectLayer && m.equirectLayer->IsDrawRequested()) { - m.equirectLayer->Update(m.predictedTracking); + m.equirectLayer->Update(m.predictedTracking, m.clearColorSwapChain); layers[layerCount++] = m.equirectLayer->Header(); m.equirectLayer->ClearRequestDraw(); } @@ -1455,7 +1490,7 @@ DeviceDelegateOculusVR::EndFrame(const bool aDiscard) { // Draw back layers for (const OculusLayerPtr& layer: m.uiLayers) { if (!layer->GetDrawInFront() && layer->IsDrawRequested() && layerCount < ovrMaxLayerCount) { - layer->Update(m.predictedTracking); + layer->Update(m.predictedTracking, m.clearColorSwapChain); layers[layerCount++] = layer->Header(); layer->ClearRequestDraw(); } @@ -1483,7 +1518,7 @@ DeviceDelegateOculusVR::EndFrame(const bool aDiscard) { // Draw front layers for (const OculusLayerPtr& layer: m.uiLayers) { if (layer->GetDrawInFront() && layer->IsDrawRequested() && layerCount < ovrMaxLayerCount) { - layer->Update(m.predictedTracking); + layer->Update(m.predictedTracking, m.clearColorSwapChain); layers[layerCount++] = layer->Header(); layer->ClearRequestDraw(); } @@ -1634,6 +1669,8 @@ DeviceDelegateOculusVR::EnterVR(const crow::BrowserEGLContext& aEGLContext) { return; } + m.clearColorSwapChain = m.CreateClearColorSwapChain(800, 450); + vrb::RenderContextPtr render = m.context.lock(); for (int i = 0; i < VRAPI_EYE_COUNT; ++i) { m.eyeSwapChains[i]->Init(render, m.renderMode, m.renderWidth, m.renderHeight); @@ -1690,6 +1727,10 @@ DeviceDelegateOculusVR::LeaveVR() { m.equirectLayer->Destroy(); } + if (m.clearColorSwapChain) { + vrapi_DestroyTextureSwapChain(m.clearColorSwapChain); + m.clearColorSwapChain = nullptr; + } m.currentFBO = nullptr; m.previousFBO = nullptr;