summaryrefslogtreecommitdiffstats
path: root/gfx/vr/ipc/VRLayerChild.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/vr/ipc/VRLayerChild.cpp')
-rw-r--r--gfx/vr/ipc/VRLayerChild.cpp151
1 files changed, 151 insertions, 0 deletions
diff --git a/gfx/vr/ipc/VRLayerChild.cpp b/gfx/vr/ipc/VRLayerChild.cpp
new file mode 100644
index 0000000000..57f69f7d2b
--- /dev/null
+++ b/gfx/vr/ipc/VRLayerChild.cpp
@@ -0,0 +1,151 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "VRLayerChild.h"
+
+#include "mozilla/dom/HTMLCanvasElement.h"
+#include "mozilla/layers/ImageBridgeChild.h"
+#include "mozilla/layers/LayersMessages.h" // for TimedTexture
+#include "mozilla/layers/SyncObject.h" // for SyncObjectClient
+#include "mozilla/StaticPrefs_dom.h"
+#include "mozilla/StaticPrefs_webgl.h"
+
+#include "ClientWebGLContext.h"
+#include "gfxPlatform.h"
+#include "GLContext.h"
+#include "GLScreenBuffer.h"
+#include "SharedSurface.h" // for SharedSurface
+#include "SharedSurfaceGL.h" // for SharedSurface
+
+namespace mozilla::gfx {
+
+VRLayerChild::VRLayerChild() { MOZ_COUNT_CTOR(VRLayerChild); }
+
+VRLayerChild::~VRLayerChild() {
+ ClearSurfaces();
+
+ MOZ_COUNT_DTOR(VRLayerChild);
+}
+
+void VRLayerChild::Initialize(dom::HTMLCanvasElement* aCanvasElement,
+ const gfx::Rect& aLeftEyeRect,
+ const gfx::Rect& aRightEyeRect) {
+ MOZ_ASSERT(aCanvasElement);
+ mLeftEyeRect = aLeftEyeRect;
+ mRightEyeRect = aRightEyeRect;
+ mCanvasElement = aCanvasElement;
+}
+
+void VRLayerChild::SetXRFramebuffer(WebGLFramebufferJS* fb) {
+ mFramebuffer = fb;
+}
+
+static constexpr bool kIsAndroid =
+#if defined(MOZ_WIDGET_ANDROID)
+ true;
+#else
+ false;
+#endif
+
+void VRLayerChild::SubmitFrame(const VRDisplayInfo& aDisplayInfo) {
+ uint64_t frameId = aDisplayInfo.GetFrameId();
+
+ // aFrameId will not increment unless the previuosly submitted
+ // frame was received by the VR thread and submitted to the VR
+ // compositor. We early-exit here in the event that SubmitFrame
+ // was called twice for the same aFrameId.
+ if (!mCanvasElement || frameId == mLastSubmittedFrameId) {
+ return;
+ }
+
+ const auto& webgl = mCanvasElement->GetWebGLContext();
+ if (!webgl) return;
+
+ // Keep the SharedSurfaceTextureClient alive long enough for
+ // 1 extra frame, accomodating overlapped asynchronous rendering.
+ mLastFrameTextureDesc = mThisFrameTextureDesc;
+
+ bool getNewFrame = true;
+ if (kIsAndroid) {
+ /**
+ * Do not blit WebGL to a SurfaceTexture until the last submitted frame is
+ * already processed and the new frame poses are ready. SurfaceTextures need
+ * to be released in the VR render thread in order to allow to be used again
+ * in the WebGLContext GLScreenBuffer producer. Not doing so causes some
+ * freezes, crashes or other undefined behaviour.
+ */
+ getNewFrame = (!mThisFrameTextureDesc ||
+ aDisplayInfo.mDisplayState.lastSubmittedFrameId ==
+ mLastSubmittedFrameId);
+ }
+ if (getNewFrame) {
+ const RefPtr<layers::ImageBridgeChild> imageBridge =
+ layers::ImageBridgeChild::GetSingleton();
+
+ auto texType = layers::TextureType::Unknown;
+ if (imageBridge) {
+ texType = layers::PreferredCanvasTextureType(imageBridge);
+ }
+ if (kIsAndroid && StaticPrefs::webgl_enable_surface_texture()) {
+ texType = layers::TextureType::AndroidNativeWindow;
+ }
+
+ webgl->Present(mFramebuffer, texType, true);
+ mThisFrameTextureDesc = webgl->GetFrontBuffer(mFramebuffer, true);
+ }
+
+ mLastSubmittedFrameId = frameId;
+
+ if (!mThisFrameTextureDesc) {
+ gfxCriticalError() << "ToSurfaceDescriptor failed in "
+ "VRLayerChild::SubmitFrame";
+ return;
+ }
+
+ SendSubmitFrame(*mThisFrameTextureDesc, frameId, mLeftEyeRect, mRightEyeRect);
+}
+
+bool VRLayerChild::IsIPCOpen() { return mIPCOpen; }
+
+void VRLayerChild::ClearSurfaces() {
+ mThisFrameTextureDesc = Nothing();
+ mLastFrameTextureDesc = Nothing();
+ const auto& webgl = mCanvasElement->GetWebGLContext();
+ if (!mFramebuffer && webgl) {
+ webgl->ClearVRSwapChain();
+ }
+}
+
+void VRLayerChild::ActorDestroy(ActorDestroyReason aWhy) { mIPCOpen = false; }
+
+// static
+PVRLayerChild* VRLayerChild::CreateIPDLActor() {
+ if (!StaticPrefs::dom_vr_enabled() && !StaticPrefs::dom_vr_webxr_enabled()) {
+ return nullptr;
+ }
+
+ VRLayerChild* c = new VRLayerChild();
+ c->AddIPDLReference();
+ return c;
+}
+
+// static
+bool VRLayerChild::DestroyIPDLActor(PVRLayerChild* actor) {
+ static_cast<VRLayerChild*>(actor)->ReleaseIPDLReference();
+ return true;
+}
+
+void VRLayerChild::AddIPDLReference() {
+ MOZ_ASSERT(mIPCOpen == false);
+ mIPCOpen = true;
+ AddRef();
+}
+void VRLayerChild::ReleaseIPDLReference() {
+ MOZ_ASSERT(mIPCOpen == false);
+ Release();
+}
+
+} // namespace mozilla::gfx