Een browserplugin voor Unity

De ontwikkeltools en -engine van Unity zijn vandaag de dag verreweg de meest gebruikte manier om toepassingen voor VR en AR te bouwen. Eerder hebben we het mogelijk gemaakt om webgebaseerde ervaringen te exporteren vanuit Unity. Vandaag zijn we enthousiast om wat vroeg werk te laten zien dat de andere manier aanpakt waarop Unity-ontwikkelaars het web willen gebruiken: als een component in hun Unity-gebaseerde virtuele omgevingen.

Voortbouwend op ons werk porting een browser engine naar vele platforms en embedding scenario’s, waaronder als Firefox Reality AR voor HoloLens 2, hebben we een nieuwe Unity-component gebouwd op basis van Servo, een moderne web engine geschreven in de taal Rust.

De Unity-engine heeft een zeer aanpasbaar multi-platform plugin-systeem met een gezond ecosysteem van plug-ins van derden, zowel open-source als proprietary. Het plugin systeem stelt ons in staat om OS-native modules te draaien en ze direct te verbinden met componenten die in de Unity scripting omgeving worden uitgevoerd.

De doelen van de experimenten waren het bouwen van een Unity native plugin en een set van Unity C # scriptcomponenten die derden in staat zouden stellen om Servo browservensters op te nemen in Unity-scènes, en optioneel, ondersteuning te bieden voor het gebruik van het browseroppervlak in VR- en AR-apps gebouwd in Unity.

Vandaag geven we een volledig functioneel prototype vrij van de Servo webbrowser die draait binnen een Unity-plugin. Dit is een vroeg stadium van ons werk, maar we weten dat de opwinding hoog is voor dit soort oplossingen, dus we hopen dat je dit prototype uitprobeert, je feedback geeft, en samen met ons dingen ermee gaat bouwen. De versie die vandaag is vrijgegeven is gericht op het macOS platform, maar we zullen binnenkort een aantal van de andere platforms toevoegen die door Servo worden ondersteund.

Aan de slag

We hebben de plugin open-sourced, op https://github.com/MozillaReality/servo-unity. Ga erheen, klik op het sterretje en fork de code, check het uit op je lokale machine, en open dan het project in Unity.

De instructies voor ontwikkelaars staan in het README bestand in de repository.

Wat het doet

Je kunt direct werken met het browservenster en de besturingselementen in de Unity-editor. Top-level config is op het ServoUnityController object. Andere belangrijke objecten in de scene zijn de ServoUnityWindow, ServoUnityNavbarController, en ServoUnityMousePointer.

De ServoUnityWindow kan overal in een Unity scene worden geplaatst. Hier hebben we het in de Mozilla paddestoel grot geplaatst (bekend bij gebruikers van Firefox Reality, door de geweldige kunstenaar Jasmin Habezai-Fekri), en voorzien van een camera manipulator die ons in staat stelt om door de scène te bewegen en te zien dat het een 3D-weergave is van de browser inhoud.

Servo heeft hoge kwaliteit media playback via het GStreamer framework, inclusief audio-ondersteuning. Hier zien we een voorbeeld van MPEG4-video, die wordt uitgevoerd in een Unity-player.

De plugin bevat aanpasbare zoekfuncties. Een grote verscheidenheid aan webinhoud kan worden bekeken met de huidige versie van Servo, met een grotere webcompatibiliteit waar actief aan wordt gewerkt (meer daarover hieronder). WebGL-inhoud werkt ook.

Hoe het werkt

Architectuur

De ontwikkeling in Unity maakt gebruik van een component-gebaseerde architectuur, waarbij Unity gebruikerscode uitvoert die is gekoppeld aan GameObjects, georganiseerd in scènes. Gebruikers passen GameObjects aan door scripts toe te voegen die worden uitgevoerd in een C#-omgeving, met behulp van de Mono runtime of de IL2CPP ahead-of-time compiler. De Unity event lifecycle is toegankelijk voor gebruikersscripts die erven van de Unity C# class MonoBehaviour. Gebruikersscripts kunnen native code aanroepen in plugins (die gewoon OS-native dynamische gedeelde objecten zijn) via het P/Invoke mechanisme van de C# runtime. In feite is Unity’s core zelf geïmplementeerd in C++ en biedt native code in plugins een tweede set van C/C++-toegankelijke interfaces om te helpen bij sommige low-level plugin taken.

Servo is zelf een complex stuk software. Door het ontwerp is het grootste deel van de niet gebruikersgerichte functionaliteit gecompileerd in een Rust bibliotheek, libservo. Voor deze eerste fase van het project, maken we gebruik van een vereenvoudigde C-compatibele interface in een andere Rust bibliotheek, libsimpleservo2. genaamd. Deze bibliotheek stelt C-calllable functies en callback hooks beschikbaar om de browser te besturen en de uitvoer te bekijken. Rond libsimpleservo2 plaatsen we native C++ abstracties die het Unity-model van threads en rendering inkapselen, en een door Unity aanroepbare set interfaces blootleggen die op hun beurt worden bediend door onze C# scriptcomponenten.

De browserinhoud in Unity

We maken een object in Unity, een instantie van ServoUnityWindow, om een instantie van Unity’s Texture2D-klasse te omhullen en deze te behandelen als een browserinhoudsdeelvenster. Bij gebruik van Unity’s OpenGL renderer, wordt de Texture2D class ondersteund door een native OpenGL texture, en we geven de OpenGL texture “naam” (d.w.z. een ID) door aan de plugin, die de texture bindt aan een framebuffer object dat de uiteindelijke gecomposeerde texture ontvangt van Servo.

Omdat we geen controle hebben over de binding van de textuur en de Unity context, maakt het huidige ontwerp voor het bijwerken van deze textuur gebruik van een blit (kopie) via Servo’s surfman-chains API. In wezen schrijft Servo’s WebRender naar een OS-specifieke oppervlaktebuffer op één thread, en dan wordt deze oppervlaktebuffer alleen-lezen gebonden aan Unity’s render thread en wordt er een textuurkopie gemaakt met OpenGL API’s. In de aanvankelijke macOS implementatie bijvoorbeeld, is de oppervlaktebuffer een IOSurface die zero-cost kan worden verplaatst tussen threads, waardoor een efficiënte implementatie mogelijk wordt waarbij de browser compositor kan schrijven in een andere thread dan de thread die de textuur in Unity weergeeft.

Controle en pagina meta-data wordt apart gecommuniceerd, via een set van API’s die zoeken en navigeren naar URL’s mogelijk maken, bijwerken van paginatitels, en de gebruikelijke terug/vooruit/stop/home knop set.

Omdat de browser inhoud en controls uiteindelijk allemaal Unity objecten zijn, kan de Unity applicatie die je bouwt deze positioneren, stylen, of programmatisch besturen op elke manier die je maar wilt.

Uitdagingen

Het project tot dit stadium brengen is niet zonder uitdagingen geweest, waarvan we er een aantal nog steeds aan het aanpakken zijn. Unity’s scripting omgeving draait grotendeels single-threaded, met uitzondering van de rendering operaties die plaatsvinden op een aparte thread op een andere cadans. Servo, echter, spawnen mogelijk tientallen lichtgewicht threads voor een verscheidenheid aan taken. We hebben ervoor gezorgd dat terugkerende werkitems van Servo worden teruggeleid naar de juiste threads in Unity. Er zijn nog wat optimalisaties te maken in het beslissen wanneer de Unity textuur vernieuwd moet worden. Op dit moment wordt de textuur elk frame vernieuwd, maar we voegen een API toe aan de embedding interface om fijnmaziger controle mogelijk te maken.

Als een incubator voor browser technologie, is Servo gericht op het ontwikkelen van nieuwe technologieën. Opmerkelijke technologie die is overgegaan van Servo naar de Gecko engine die Firefox aandrijft zijn onder andere de GPU-gebaseerde rendering engine WebRender, en de CSS engine Stylo. Deze successen terzijde, volledige web compatibiliteit is nog steeds een gebied waar Servo een belangrijke achterstand heeft, omdat we ons voornamelijk hebben gericht op grote verbeteringen voor de gebruiker en specifieke ervaringen over de lange staart van het web. Een recente inspanning van de Servo-gemeenschap heeft grote vooruitgang gezien in Servo’s webcompatibiliteit, dus we verwachten dat de subset van het web door Servo bladerbaar snel zal blijven groeien.

Ontwikkelingsplannen

Ondersteuning van het volledige scala van platforms die momenteel worden ondersteund door Servo is onze eerste follow-up ontwikkelingsprioriteit, met Windows Win32 en Windows UWP ondersteuning bovenaan de lijst. Velen van u hebben onze Firefox Reality AR voor HoloLens 2 app gezien, en UWP-ondersteuning zal u in staat stellen om Servo te bouwen in een uw eigen AR-apps voor het HoloLens-platform met behulp van dezelfde onderliggende browser engine.

We zouden ook graag een grotere subset van de volledige browser mogelijkheden ondersteunen. Hoog op de lijst staat ondersteuning voor meerdere vensters. We werken momenteel aan het aanpassen van de plugin van de libsimpleservo2 interface naar een nieuwe interface die applicaties in staat stelt om meerdere vensters, tabbladen, en functies zoals geschiedenis, bladwijzers en meer te implementeren.

Deze eerste release is gericht op het web bladerbaar door middel van 2D webpagina’s. Servo ondersteunt ook het immersieve web via de WebXR API, en we onderzoeken of we WebXR kunnen koppelen aan Unity’s XR hardware ondersteuning via de plugin interface. We zullen beginnen met ondersteuning voor het bekijken van 360 ° video, waarvan we weten van onze Firefox Reality-gebruikersbasis is een primaire use case voor de browser.

Tot slot…

Of het nu gaat om een mediaspeler, een in-game interface naar het open web, browser-als-UI, het binnenhalen van specifieke webervaringen, of de talloze andere mogelijkheden, we kunnen niet wachten om een aantal van de fantasierijke manieren te zien waarop ontwikkelaars Servo’s kracht en prestaties zullen benutten binnen door Unity gebouwde apps.