Skip to content

Commit

Permalink
Implement GPU Accelerated VR Overlay (#944)
Browse files Browse the repository at this point in the history
  • Loading branch information
BenjaminZehowlt authored Oct 21, 2024
1 parent 411f509 commit f9686ad
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 129 deletions.
1 change: 0 additions & 1 deletion Dotnet/Cef/CefService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ internal void Init()
cefSettings.CefCommandLineArgs.Add("disable-pdf-extension");
cefSettings.CefCommandLineArgs["autoplay-policy"] = "no-user-gesture-required";
cefSettings.CefCommandLineArgs.Add("disable-web-security");
cefSettings.SetOffScreenRenderingBestPerformanceArgs(); // causes white screen sometimes?

if (WebApi.ProxySet)
{
Expand Down
178 changes: 62 additions & 116 deletions Dotnet/Overlay/OffScreenBrowser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,116 +10,76 @@
using CefSharp.Structs;
using SharpDX.Direct3D11;
using System;
using System.Runtime.InteropServices;
using System.Threading;
using SharpDX.Direct3D;
using SharpDX.Mathematics.Interop;
using Range = CefSharp.Structs.Range;

namespace VRCX
{
public class OffScreenBrowser : ChromiumWebBrowser, IRenderHandler
{
private readonly ReaderWriterLockSlim _paintBufferLock;
private GCHandle _paintBuffer;
private int _width;
private int _height;
private Device _device;
private Device1 _device1;
private DeviceMultithread _deviceMultithread;
private Query _query;
private Texture2D _renderTarget;

public OffScreenBrowser(string address, int width, int height)
: base(
address,
new BrowserSettings()
{
DefaultEncoding = "UTF-8"
}
)
: base(address, automaticallyCreateBrowser: false)
{
_paintBufferLock = new ReaderWriterLockSlim();
var windowInfo = new WindowInfo();
windowInfo.SetAsWindowless(IntPtr.Zero);
windowInfo.WindowlessRenderingEnabled = true;
windowInfo.SharedTextureEnabled = true;
windowInfo.Width = width;
windowInfo.Height = height;

var browserSettings = new BrowserSettings()
{
DefaultEncoding = "UTF-8",
WindowlessFrameRate = 60
};

CreateBrowser(windowInfo, browserSettings);

Size = new System.Drawing.Size(width, height);
RenderHandler = this;

JavascriptBindings.ApplyVrJavascriptBindings(JavascriptObjectRepository);
}

public new void Dispose()
public void UpdateRender(Device device, Texture2D renderTarget)
{
RenderHandler = null;
base.Dispose();
_device = device;
_device1 = _device.QueryInterface<Device1>();

_deviceMultithread?.Dispose();
_deviceMultithread = _device.QueryInterfaceOrNull<DeviceMultithread>();
_deviceMultithread?.SetMultithreadProtected(true);

_paintBufferLock.EnterWriteLock();
try
{
if (_paintBuffer.IsAllocated == true)
{
_paintBuffer.Free();
}
}
finally
_renderTarget = renderTarget;

_query?.Dispose();
_query = new Query(_device, new QueryDescription
{
_paintBufferLock.ExitWriteLock();
}

_paintBufferLock.Dispose();
Type = QueryType.Event,
Flags = QueryFlags.None
});
}

public void RenderToTexture(Texture2D texture)
public new void Dispose()
{
// Safeguard against uninitialized texture
if (texture == null)
return;

_paintBufferLock.EnterReadLock();
try
{
if (_width > 0 &&
_height > 0)
{
var context = texture.Device.ImmediateContext;
var dataBox = context.MapSubresource(
texture,
0,
MapMode.WriteDiscard,
MapFlags.None
);
if (dataBox.IsEmpty == false)
{
var sourcePtr = _paintBuffer.AddrOfPinnedObject();
var destinationPtr = dataBox.DataPointer;
var pitch = _width * 4;
var rowPitch = dataBox.RowPitch;
if (pitch == rowPitch)
{
WinApi.RtlCopyMemory(
destinationPtr,
sourcePtr,
(uint)(_width * _height * 4)
);
}
else
{
for (var y = _height; y > 0; --y)
{
WinApi.RtlCopyMemory(
destinationPtr,
sourcePtr,
(uint)pitch
);
sourcePtr += pitch;
destinationPtr += rowPitch;
}
}
}
context.UnmapSubresource(texture, 0);
}
}
finally
{
_paintBufferLock.ExitReadLock();
}
RenderHandler = null;
base.Dispose();
}

ScreenInfo? IRenderHandler.GetScreenInfo()
{
return null;
return new ScreenInfo
{
DeviceScaleFactor = 1.0F
};
}

bool IRenderHandler.GetScreenPoint(int viewX, int viewY, out int screenX, out int screenY)
Expand All @@ -136,7 +96,24 @@ Rect IRenderHandler.GetViewRect()

void IRenderHandler.OnAcceleratedPaint(PaintElementType type, Rect dirtyRect, AcceleratedPaintInfo paintInfo)
{
// NOT USED
if (type != PaintElementType.View)
return;

if (_device == null)
return;

using Texture2D cefTexture = _device1.OpenSharedResource1<Texture2D>(paintInfo.SharedTextureHandle);
_device.ImmediateContext.CopyResource(cefTexture, _renderTarget);
_device.ImmediateContext.End(_query);
_device.ImmediateContext.Flush();

RawBool q = _device.ImmediateContext.GetData<RawBool>(_query, AsynchronousFlags.DoNotFlush);

while (!q)
{
Thread.Yield();
q = _device.ImmediateContext.GetData<RawBool>(_query, AsynchronousFlags.DoNotFlush);
}
}

void IRenderHandler.OnCursorChange(IntPtr cursor, CursorType type, CursorInfo customCursorInfo)
Expand All @@ -149,37 +126,6 @@ void IRenderHandler.OnImeCompositionRangeChanged(Range selectedRange, Rect[] cha

void IRenderHandler.OnPaint(PaintElementType type, Rect dirtyRect, IntPtr buffer, int width, int height)
{
if (type == PaintElementType.View)
{
_paintBufferLock.EnterWriteLock();
try
{
if (_width != width ||
_height != height)
{
_width = width;
_height = height;
if (_paintBuffer.IsAllocated == true)
{
_paintBuffer.Free();
}
_paintBuffer = GCHandle.Alloc(
new byte[_width * _height * 4],
GCHandleType.Pinned
);
}

WinApi.RtlCopyMemory(
_paintBuffer.AddrOfPinnedObject(),
buffer,
(uint)(width * height * 4)
);
}
finally
{
_paintBufferLock.ExitWriteLock();
}
}
}

void IRenderHandler.OnPopupShow(bool show)
Expand Down
61 changes: 49 additions & 12 deletions Dotnet/Overlay/VRCXVR.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@
using SharpDX.DXGI;
using Valve.VR;
using Device = SharpDX.Direct3D11.Device;
using Device1 = SharpDX.Direct3D11.Device1;
using Device2 = SharpDX.Direct3D11.Device2;
using Device3 = SharpDX.Direct3D11.Device3;
using Device4 = SharpDX.Direct3D11.Device4;

namespace VRCX
{
Expand Down Expand Up @@ -87,7 +91,8 @@ private void SetupTextures()
{
Factory f = new Factory1();
_device = new Device(f.GetAdapter(OpenVR.System.GetD3D9AdapterIndex()),
DeviceCreationFlags.SingleThreaded | DeviceCreationFlags.BgraSupport);
DeviceCreationFlags.BgraSupport);
UpgradeDevice();

_texture1?.Dispose();
_texture1 = new Texture2D(
Expand All @@ -100,12 +105,11 @@ private void SetupTextures()
ArraySize = 1,
Format = Format.B8G8R8A8_UNorm,
SampleDescription = new SampleDescription(1, 0),
Usage = ResourceUsage.Dynamic,
BindFlags = BindFlags.ShaderResource,
CpuAccessFlags = CpuAccessFlags.Write
BindFlags = BindFlags.ShaderResource
}
);

_browser1?.UpdateRender(_device, _texture1);

_texture2?.Dispose();
_texture2 = new Texture2D(
_device,
Expand All @@ -117,11 +121,48 @@ private void SetupTextures()
ArraySize = 1,
Format = Format.B8G8R8A8_UNorm,
SampleDescription = new SampleDescription(1, 0),
Usage = ResourceUsage.Dynamic,
BindFlags = BindFlags.ShaderResource,
CpuAccessFlags = CpuAccessFlags.Write
BindFlags = BindFlags.ShaderResource
}
);
_browser2?.UpdateRender(_device, _texture2);
}

private void UpgradeDevice()
{
Device5 device5 = _device.QueryInterfaceOrNull<Device5>();
if (device5 != null)
{
_device.Dispose();
_device = device5;
return;
}
Device4 device4 = _device.QueryInterfaceOrNull<Device4>();
if (device4 != null)
{
_device.Dispose();
_device = device4;
return;
}
Device3 device3 = _device.QueryInterfaceOrNull<Device3>();
if (device3 != null)
{
_device.Dispose();
_device = device3;
return;
}
Device2 device2 = _device.QueryInterfaceOrNull<Device2>();
if (device2 != null)
{
_device.Dispose();
_device = device2;
return;
}
Device1 device1 = _device.QueryInterfaceOrNull<Device1>();
if (device1 != null)
{
_device.Dispose();
_device = device1;
}
}

private void ThreadLoop()
Expand Down Expand Up @@ -152,10 +193,6 @@ private void ThreadLoop()

while (_thread != null)
{
if (_wristOverlayActive)
_browser1.RenderToTexture(_texture1);
if (_hmdOverlayActive)
_browser2.RenderToTexture(_texture2);
try
{
Thread.Sleep(32);
Expand Down

0 comments on commit f9686ad

Please sign in to comment.