VRLayerChild.cpp (4659B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "VRLayerChild.h" 8 9 #include "mozilla/dom/HTMLCanvasElement.h" 10 #include "mozilla/layers/ImageBridgeChild.h" 11 #include "mozilla/layers/LayersMessages.h" // for TimedTexture 12 #include "mozilla/layers/SyncObject.h" // for SyncObjectClient 13 #include "mozilla/StaticPrefs_dom.h" 14 #include "mozilla/StaticPrefs_webgl.h" 15 16 #include "ClientWebGLContext.h" 17 #include "gfxPlatform.h" 18 #include "GLContext.h" 19 #include "GLScreenBuffer.h" 20 #include "SharedSurface.h" // for SharedSurface 21 #include "SharedSurfaceGL.h" // for SharedSurface 22 23 namespace mozilla::gfx { 24 25 VRLayerChild::VRLayerChild() { MOZ_COUNT_CTOR(VRLayerChild); } 26 27 VRLayerChild::~VRLayerChild() { 28 ClearSurfaces(); 29 30 MOZ_COUNT_DTOR(VRLayerChild); 31 } 32 33 void VRLayerChild::Initialize(dom::HTMLCanvasElement* aCanvasElement, 34 const gfx::Rect& aLeftEyeRect, 35 const gfx::Rect& aRightEyeRect) { 36 MOZ_ASSERT(aCanvasElement); 37 mLeftEyeRect = aLeftEyeRect; 38 mRightEyeRect = aRightEyeRect; 39 mCanvasElement = aCanvasElement; 40 } 41 42 void VRLayerChild::SetXRFramebuffer(WebGLFramebufferJS* fb) { 43 mFramebuffer = fb; 44 } 45 46 static constexpr bool kIsAndroid = 47 #if defined(MOZ_WIDGET_ANDROID) 48 true; 49 #else 50 false; 51 #endif 52 53 void VRLayerChild::SubmitFrame(const VRDisplayInfo& aDisplayInfo) { 54 uint64_t frameId = aDisplayInfo.GetFrameId(); 55 56 // aFrameId will not increment unless the previuosly submitted 57 // frame was received by the VR thread and submitted to the VR 58 // compositor. We early-exit here in the event that SubmitFrame 59 // was called twice for the same aFrameId. 60 if (!mCanvasElement || frameId == mLastSubmittedFrameId) { 61 return; 62 } 63 64 const auto& webgl = mCanvasElement->GetWebGLContext(); 65 if (!webgl) return; 66 67 // Keep the SharedSurfaceTextureClient alive long enough for 68 // 1 extra frame, accomodating overlapped asynchronous rendering. 69 mLastFrameTextureDesc = mThisFrameTextureDesc; 70 71 bool getNewFrame = true; 72 if (kIsAndroid) { 73 /** 74 * Do not blit WebGL to a SurfaceTexture until the last submitted frame is 75 * already processed and the new frame poses are ready. SurfaceTextures need 76 * to be released in the VR render thread in order to allow to be used again 77 * in the WebGLContext GLScreenBuffer producer. Not doing so causes some 78 * freezes, crashes or other undefined behaviour. 79 */ 80 getNewFrame = (!mThisFrameTextureDesc || 81 aDisplayInfo.mDisplayState.lastSubmittedFrameId == 82 mLastSubmittedFrameId); 83 } 84 if (getNewFrame) { 85 const RefPtr<layers::ImageBridgeChild> imageBridge = 86 layers::ImageBridgeChild::GetSingleton(); 87 88 auto texType = layers::TextureType::Unknown; 89 if (imageBridge) { 90 texType = layers::PreferredCanvasTextureType(imageBridge); 91 } 92 if (kIsAndroid && StaticPrefs::webgl_enable_surface_texture()) { 93 texType = layers::TextureType::AndroidNativeWindow; 94 } 95 96 webgl->Present(mFramebuffer, texType, true); 97 mThisFrameTextureDesc = webgl->GetFrontBuffer(mFramebuffer, true); 98 } 99 100 mLastSubmittedFrameId = frameId; 101 102 if (!mThisFrameTextureDesc) { 103 gfxCriticalError() << "ToSurfaceDescriptor failed in " 104 "VRLayerChild::SubmitFrame"; 105 return; 106 } 107 108 SendSubmitFrame(*mThisFrameTextureDesc, frameId, mLeftEyeRect, mRightEyeRect); 109 } 110 111 bool VRLayerChild::IsIPCOpen() { return mIPCOpen; } 112 113 void VRLayerChild::ClearSurfaces() { 114 mThisFrameTextureDesc = Nothing(); 115 mLastFrameTextureDesc = Nothing(); 116 const auto& webgl = mCanvasElement->GetWebGLContext(); 117 if (!mFramebuffer && webgl) { 118 webgl->ClearVRSwapChain(); 119 } 120 } 121 122 void VRLayerChild::ActorDestroy(ActorDestroyReason aWhy) { mIPCOpen = false; } 123 124 // static 125 PVRLayerChild* VRLayerChild::CreateIPDLActor() { 126 if (!StaticPrefs::dom_vr_enabled() && !StaticPrefs::dom_vr_webxr_enabled()) { 127 return nullptr; 128 } 129 130 VRLayerChild* c = new VRLayerChild(); 131 c->AddIPDLReference(); 132 return c; 133 } 134 135 // static 136 bool VRLayerChild::DestroyIPDLActor(PVRLayerChild* actor) { 137 static_cast<VRLayerChild*>(actor)->ReleaseIPDLReference(); 138 return true; 139 } 140 141 void VRLayerChild::AddIPDLReference() { 142 MOZ_ASSERT(mIPCOpen == false); 143 mIPCOpen = true; 144 AddRef(); 145 } 146 void VRLayerChild::ReleaseIPDLReference() { 147 MOZ_ASSERT(mIPCOpen == false); 148 Release(); 149 } 150 151 } // namespace mozilla::gfx