|
| 1 | +--- |
| 2 | +title: Graphics binding |
| 3 | +description: Setup of graphics bindings and use cases |
| 4 | +author: florianborn71 |
| 5 | +manager: jlyons |
| 6 | +services: azure-remote-rendering |
| 7 | +titleSuffix: Azure Remote Rendering |
| 8 | +ms.author: flborn |
| 9 | +ms.date: 12/11/2019 |
| 10 | +ms.topic: conceptual |
| 11 | +ms.service: azure-remote-rendering |
| 12 | +--- |
| 13 | +# Graphics binding |
| 14 | + |
| 15 | +To be able to use Azure Remote Rendering in a custom application, it needs to be integrated into the application's rendering pipeline. This integration is the responsibility of the graphics binding. |
| 16 | + |
| 17 | +Once set up, the graphics binding gives access to various functions that affect the rendered image. These functions can be separated into two categories: general functions that are always available and specific functions that are only relevant for the selected `Microsoft.Azure.RemoteRendering.GraphicsApiType`. |
| 18 | + |
| 19 | +## Graphics binding in Unity |
| 20 | + |
| 21 | +In Unity, the entire binding is handled by the `RemoteUnityClientInit` struct passed into `RemoteManagerUnity.InitializeManager`. To set the graphics mode, the `GraphicsApiType` field has to be set to the chosen binding. The field will be automatically populated depending on whether an XRDevice is present. The behavior can be manually overridden with the following behaviors: |
| 22 | + |
| 23 | +* **HoloLens 2**: the [Windows Mixed Reality](#windows-mixed-reality) graphics binding is always used. |
| 24 | +* **Flat UWP desktop app**: [Simulation](#simulation) is always used. To use this mode, make sure to follow the steps in [Tutorial: Setting up a Unity project from scratch](../tutorials/unity/project-setup.md). |
| 25 | +* **Unity editor**: [Simulation](#simulation) is always used unless a WMR VR headset is connected in which case ARR will be disabled to allow to debug the non-ARR related parts of the application. See also [holographic remoting](../how-tos/unity/holographic-remoting.md). |
| 26 | + |
| 27 | +The only other relevant part for Unity is accessing the [basic binding](#access), all the other sections below can be skipped. |
| 28 | + |
| 29 | +## Graphics binding setup in custom applications |
| 30 | + |
| 31 | +To select a graphics binding, take the following two steps: First, the graphics binding has to be statically initialized when the program is initialized: |
| 32 | + |
| 33 | +``` cs |
| 34 | +RemoteRenderingInitialization managerInit = new RemoteRenderingInitialization; |
| 35 | +managerInit.graphicsApi = GraphicsApiType.WmrD3D11; |
| 36 | +managerInit.connectionType = ConnectionType.General; |
| 37 | +managerInit.right = ///... |
| 38 | +RemoteManagerStatic.StartupRemoteRendering(managerInit); |
| 39 | +``` |
| 40 | + |
| 41 | +The call above is necessary to initialize Azure Remote Rendering into the holographic APIs. This function must be called before any holographic API is called and before any other Remote Rendering APIs are accessed. Similarly, the corresponding de-init function `RemoteManagerStatic.ShutdownRemoteRendering();` should be called after no holographic APIs are being called anymore. |
| 42 | + |
| 43 | +## <span id="access">Accessing graphics binding |
| 44 | + |
| 45 | +Once a client is set up, the basic graphics binding can be accessed with the `AzureSession.GraphicsBinding` getter. As an example, the last frame statistics can be retrieved like this: |
| 46 | + |
| 47 | +``` cs |
| 48 | +AzureSession currentSesson = ...; |
| 49 | +if (currentSesson.GraphicsBinding) |
| 50 | +{ |
| 51 | + FrameStatistics frameStatistics; |
| 52 | + if (session.GraphicsBinding.GetLastFrameStatistics(out frameStatistics) == Result.Success) |
| 53 | + { |
| 54 | + ... |
| 55 | + } |
| 56 | +} |
| 57 | +``` |
| 58 | + |
| 59 | +## Graphic APIs |
| 60 | + |
| 61 | +There are currently two graphics APIs that can be selected, `WmrD3D11` and `SimD3D11`. A third one `Headless` exists but is not yet supported on the client side. |
| 62 | + |
| 63 | +### Windows Mixed Reality |
| 64 | + |
| 65 | +`GraphicsApiType.WmrD3D11` is the default binding to run on HoloLens 2. It will create the `GraphicsBindingWmrD3d11` binding. In this mode Azure Remote Rendering hooks directly into the holographic APIs. |
| 66 | + |
| 67 | +To access the derived graphics bindings, the base `GraphicsBinding` has to be cast. |
| 68 | +There are two things that need to be done to use the WMR binding: |
| 69 | + |
| 70 | +#### Inform Remote Rendering of the used coordinate system |
| 71 | + |
| 72 | +``` cs |
| 73 | +AzureSession currentSesson = ...; |
| 74 | +IntPtr ptr = ...; // native pointer to ISpatialCoordinateSystem |
| 75 | +GraphicsBindingWmrD3d11 wmrBinding = (currentSession.GraphicsBinding as GraphicsBindingWmrD3d11); |
| 76 | +if (binding.UpdateUserCoordinateSystem(ptr) == Result.Success) |
| 77 | +{ |
| 78 | + ... |
| 79 | +} |
| 80 | +``` |
| 81 | + |
| 82 | +Where the above `ptr` must be a pointer to a native `ABI::Windows::Perception::Spatial::ISpatialCoordinateSystem` object that defines the world space coordinate system in which coordinates in the API are expressed in. |
| 83 | + |
| 84 | +#### Render remote image |
| 85 | + |
| 86 | +At the start of each frame the remote frame needs to be rendered into the back buffer. This is done by calling `BlitRemoteFrame`, which will fill both color and depth information into the currently bound render target. Thus it is important that this is done after binding the back buffer as a render target. |
| 87 | + |
| 88 | +``` cs |
| 89 | +AzureSession currentSesson = ...; |
| 90 | +GraphicsBindingWmrD3d11 wmrBinding = (currentSession.GraphicsBinding as GraphicsBindingWmrD3d11); |
| 91 | +binding.BlitRemoteFrame(); |
| 92 | +``` |
| 93 | + |
| 94 | +### Simulation |
| 95 | + |
| 96 | +`GraphicsApiType.SimD3D11` is the simulation binding and if selected it creates the `GraphicsBindingSimD3d11` graphics binding. This interface is used to simulate head movement, for example in a desktop application and renders a monoscopic image. |
| 97 | +The setup is a bit more involved and works as follows: |
| 98 | + |
| 99 | +#### Create proxy render target |
| 100 | + |
| 101 | +Remote and local content needs to be rendered to an offscreen color / depth render target called 'proxy' using |
| 102 | +the proxy camera data provided by the `GraphicsBindingSimD3d11.Update` function. The proxy must match the resolution of the back buffer. Once a session is ready, `GraphicsBindingSimD3d11.InitSimulation` needs to be called before connecting to it: |
| 103 | + |
| 104 | +``` cs |
| 105 | +AzureSession currentSesson = ...; |
| 106 | +IntPtr d3dDevice = ...; // native pointer to ID3D11Device |
| 107 | +IntPtr color = ...; // native pointer to ID3D11Texture2D |
| 108 | +IntPtr depth = ...; // native pointer to ID3D11Texture2D |
| 109 | +float refreshRate = 60.0f; // Monitor refresh rate up to 60hz. |
| 110 | +bool flipBlitRemoteFrameTextureVertically = false; |
| 111 | +bool flipReprojectTextureVertically = false; |
| 112 | +GraphicsBindingSimD3d11 simBinding = (currentSession.GraphicsBinding as GraphicsBindingSimD3d11); |
| 113 | +simBinding.InitSimulation(d3dDevice, depth, color, refreshRate, flipBlitRemoteFrameTextureVertically, flipReprojectTextureVertically); |
| 114 | +``` |
| 115 | + |
| 116 | +The init function needs to be provided with pointers to the native d3d-device as well as to the color and depth texture of the proxy render target. Once initialized, `AzureSession.ConnectToRuntime` and `DisconnectFromRuntime` can be called multiple times but when switching to a different session, `GraphicsBindingSimD3d11.DeinitSimulation` needs to be called first on the old session before `GraphicsBindingSimD3d11.InitSimulation` can be called on another session. |
| 117 | + |
| 118 | +#### Render loop update |
| 119 | + |
| 120 | +The render loop update consists of multiple steps: |
| 121 | + |
| 122 | +1. Each frame, before any rendering takes place, `GraphicsBindingSimD3d11.Update` is called with the current camera transform that is sent over to the server to be rendered. At the same time the returned proxy transform should be applied to the proxy camera to render into the proxy render target. |
| 123 | +If the returned proxy update `SimulationUpdate.frameId` is null, there is no remote data yet. In this case, instead of rendering into the proxy render target, any local content should be rendered to the back buffer directly using the current camera data and the next two steps are skipped. |
| 124 | +1. The application should now bind the proxy render target and call `GraphicsBindingSimD3d11.BlitRemoteFrameToProxy`. This will fill the remote color and depth information into the proxy render target. Any local content can now be rendered onto the proxy using the proxy camera transform. |
| 125 | +1. Next, the back buffer needs to be bound as a render target and `GraphicsBindingSimD3d11.ReprojectProxy` called at which point the back buffer can be presented. |
| 126 | + |
| 127 | +``` cs |
| 128 | +AzureSession currentSesson = ...; |
| 129 | +GraphicsBindingSimD3d11 simBinding = (currentSession.GraphicsBinding as GraphicsBindingSimD3d11); |
| 130 | +SimulationUpdate update = new SimulationUpdate(); |
| 131 | +// Fill out camera data with current camera data |
| 132 | +... |
| 133 | +SimulationUpdate proxyUpdate = new SimulationUpdate(); |
| 134 | +simBinding.Update(update, out proxyUpdate); |
| 135 | +// Is the frame data valid? |
| 136 | +if (proxyUpdate.frameId != 0) |
| 137 | +{ |
| 138 | + // Bind proxy render target |
| 139 | + simBinding.BlitRemoteFrameToProxy(); |
| 140 | + // Use proxy camera data to render local content |
| 141 | + ... |
| 142 | + // Bind back buffer |
| 143 | + simBinding.ReprojectProxy(); |
| 144 | +} |
| 145 | +else |
| 146 | +{ |
| 147 | + // Bind back buffer |
| 148 | + // Use current camera data to render local content |
| 149 | + ... |
| 150 | +} |
| 151 | +``` |
| 152 | + |
| 153 | +## Next steps |
| 154 | + |
| 155 | +* [Tutorial: Setting up a Unity project from scratch](../tutorials/unity/project-setup.md) |
0 commit comments