mirror of
https://github.com/MrUnknownDE/VRCX.git
synced 2026-05-07 06:56:04 +02:00
Implement GPU Accelerated VR Overlay (#944)
This commit is contained in:
@@ -51,7 +51,6 @@ namespace VRCX
|
|||||||
cefSettings.CefCommandLineArgs.Add("disable-pdf-extension");
|
cefSettings.CefCommandLineArgs.Add("disable-pdf-extension");
|
||||||
cefSettings.CefCommandLineArgs["autoplay-policy"] = "no-user-gesture-required";
|
cefSettings.CefCommandLineArgs["autoplay-policy"] = "no-user-gesture-required";
|
||||||
cefSettings.CefCommandLineArgs.Add("disable-web-security");
|
cefSettings.CefCommandLineArgs.Add("disable-web-security");
|
||||||
cefSettings.SetOffScreenRenderingBestPerformanceArgs(); // causes white screen sometimes?
|
|
||||||
|
|
||||||
if (WebApi.ProxySet)
|
if (WebApi.ProxySet)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -10,29 +10,38 @@ using CefSharp.OffScreen;
|
|||||||
using CefSharp.Structs;
|
using CefSharp.Structs;
|
||||||
using SharpDX.Direct3D11;
|
using SharpDX.Direct3D11;
|
||||||
using System;
|
using System;
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
using SharpDX.Direct3D;
|
||||||
|
using SharpDX.Mathematics.Interop;
|
||||||
using Range = CefSharp.Structs.Range;
|
using Range = CefSharp.Structs.Range;
|
||||||
|
|
||||||
namespace VRCX
|
namespace VRCX
|
||||||
{
|
{
|
||||||
public class OffScreenBrowser : ChromiumWebBrowser, IRenderHandler
|
public class OffScreenBrowser : ChromiumWebBrowser, IRenderHandler
|
||||||
{
|
{
|
||||||
private readonly ReaderWriterLockSlim _paintBufferLock;
|
private Device _device;
|
||||||
private GCHandle _paintBuffer;
|
private Device1 _device1;
|
||||||
private int _width;
|
private DeviceMultithread _deviceMultithread;
|
||||||
private int _height;
|
private Query _query;
|
||||||
|
private Texture2D _renderTarget;
|
||||||
|
|
||||||
public OffScreenBrowser(string address, int width, int height)
|
public OffScreenBrowser(string address, int width, int height)
|
||||||
: base(
|
: base(address, automaticallyCreateBrowser: false)
|
||||||
address,
|
|
||||||
new BrowserSettings()
|
|
||||||
{
|
{
|
||||||
DefaultEncoding = "UTF-8"
|
var windowInfo = new WindowInfo();
|
||||||
}
|
windowInfo.SetAsWindowless(IntPtr.Zero);
|
||||||
)
|
windowInfo.WindowlessRenderingEnabled = true;
|
||||||
|
windowInfo.SharedTextureEnabled = true;
|
||||||
|
windowInfo.Width = width;
|
||||||
|
windowInfo.Height = height;
|
||||||
|
|
||||||
|
var browserSettings = new BrowserSettings()
|
||||||
{
|
{
|
||||||
_paintBufferLock = new ReaderWriterLockSlim();
|
DefaultEncoding = "UTF-8",
|
||||||
|
WindowlessFrameRate = 60
|
||||||
|
};
|
||||||
|
|
||||||
|
CreateBrowser(windowInfo, browserSettings);
|
||||||
|
|
||||||
Size = new System.Drawing.Size(width, height);
|
Size = new System.Drawing.Size(width, height);
|
||||||
RenderHandler = this;
|
RenderHandler = this;
|
||||||
@@ -40,86 +49,37 @@ namespace VRCX
|
|||||||
JavascriptBindings.ApplyVrJavascriptBindings(JavascriptObjectRepository);
|
JavascriptBindings.ApplyVrJavascriptBindings(JavascriptObjectRepository);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void UpdateRender(Device device, Texture2D renderTarget)
|
||||||
|
{
|
||||||
|
_device = device;
|
||||||
|
_device1 = _device.QueryInterface<Device1>();
|
||||||
|
|
||||||
|
_deviceMultithread?.Dispose();
|
||||||
|
_deviceMultithread = _device.QueryInterfaceOrNull<DeviceMultithread>();
|
||||||
|
_deviceMultithread?.SetMultithreadProtected(true);
|
||||||
|
|
||||||
|
_renderTarget = renderTarget;
|
||||||
|
|
||||||
|
_query?.Dispose();
|
||||||
|
_query = new Query(_device, new QueryDescription
|
||||||
|
{
|
||||||
|
Type = QueryType.Event,
|
||||||
|
Flags = QueryFlags.None
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public new void Dispose()
|
public new void Dispose()
|
||||||
{
|
{
|
||||||
RenderHandler = null;
|
RenderHandler = null;
|
||||||
base.Dispose();
|
base.Dispose();
|
||||||
|
|
||||||
_paintBufferLock.EnterWriteLock();
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (_paintBuffer.IsAllocated == true)
|
|
||||||
{
|
|
||||||
_paintBuffer.Free();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
_paintBufferLock.ExitWriteLock();
|
|
||||||
}
|
|
||||||
|
|
||||||
_paintBufferLock.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RenderToTexture(Texture2D texture)
|
|
||||||
{
|
|
||||||
// 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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ScreenInfo? IRenderHandler.GetScreenInfo()
|
ScreenInfo? IRenderHandler.GetScreenInfo()
|
||||||
{
|
{
|
||||||
return null;
|
return new ScreenInfo
|
||||||
|
{
|
||||||
|
DeviceScaleFactor = 1.0F
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IRenderHandler.GetScreenPoint(int viewX, int viewY, out int screenX, out int screenY)
|
bool IRenderHandler.GetScreenPoint(int viewX, int viewY, out int screenX, out int screenY)
|
||||||
@@ -136,7 +96,24 @@ namespace VRCX
|
|||||||
|
|
||||||
void IRenderHandler.OnAcceleratedPaint(PaintElementType type, Rect dirtyRect, AcceleratedPaintInfo paintInfo)
|
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)
|
void IRenderHandler.OnCursorChange(IntPtr cursor, CursorType type, CursorInfo customCursorInfo)
|
||||||
@@ -149,37 +126,6 @@ namespace VRCX
|
|||||||
|
|
||||||
void IRenderHandler.OnPaint(PaintElementType type, Rect dirtyRect, IntPtr buffer, int width, int height)
|
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)
|
void IRenderHandler.OnPopupShow(bool show)
|
||||||
|
|||||||
+48
-11
@@ -16,6 +16,10 @@ using SharpDX.Direct3D11;
|
|||||||
using SharpDX.DXGI;
|
using SharpDX.DXGI;
|
||||||
using Valve.VR;
|
using Valve.VR;
|
||||||
using Device = SharpDX.Direct3D11.Device;
|
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
|
namespace VRCX
|
||||||
{
|
{
|
||||||
@@ -87,7 +91,8 @@ namespace VRCX
|
|||||||
{
|
{
|
||||||
Factory f = new Factory1();
|
Factory f = new Factory1();
|
||||||
_device = new Device(f.GetAdapter(OpenVR.System.GetD3D9AdapterIndex()),
|
_device = new Device(f.GetAdapter(OpenVR.System.GetD3D9AdapterIndex()),
|
||||||
DeviceCreationFlags.SingleThreaded | DeviceCreationFlags.BgraSupport);
|
DeviceCreationFlags.BgraSupport);
|
||||||
|
UpgradeDevice();
|
||||||
|
|
||||||
_texture1?.Dispose();
|
_texture1?.Dispose();
|
||||||
_texture1 = new Texture2D(
|
_texture1 = new Texture2D(
|
||||||
@@ -100,11 +105,10 @@ namespace VRCX
|
|||||||
ArraySize = 1,
|
ArraySize = 1,
|
||||||
Format = Format.B8G8R8A8_UNorm,
|
Format = Format.B8G8R8A8_UNorm,
|
||||||
SampleDescription = new SampleDescription(1, 0),
|
SampleDescription = new SampleDescription(1, 0),
|
||||||
Usage = ResourceUsage.Dynamic,
|
BindFlags = BindFlags.ShaderResource
|
||||||
BindFlags = BindFlags.ShaderResource,
|
|
||||||
CpuAccessFlags = CpuAccessFlags.Write
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
_browser1?.UpdateRender(_device, _texture1);
|
||||||
|
|
||||||
_texture2?.Dispose();
|
_texture2?.Dispose();
|
||||||
_texture2 = new Texture2D(
|
_texture2 = new Texture2D(
|
||||||
@@ -117,11 +121,48 @@ namespace VRCX
|
|||||||
ArraySize = 1,
|
ArraySize = 1,
|
||||||
Format = Format.B8G8R8A8_UNorm,
|
Format = Format.B8G8R8A8_UNorm,
|
||||||
SampleDescription = new SampleDescription(1, 0),
|
SampleDescription = new SampleDescription(1, 0),
|
||||||
Usage = ResourceUsage.Dynamic,
|
BindFlags = BindFlags.ShaderResource
|
||||||
BindFlags = BindFlags.ShaderResource,
|
|
||||||
CpuAccessFlags = CpuAccessFlags.Write
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
_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()
|
private void ThreadLoop()
|
||||||
@@ -152,10 +193,6 @@ namespace VRCX
|
|||||||
|
|
||||||
while (_thread != null)
|
while (_thread != null)
|
||||||
{
|
{
|
||||||
if (_wristOverlayActive)
|
|
||||||
_browser1.RenderToTexture(_texture1);
|
|
||||||
if (_hmdOverlayActive)
|
|
||||||
_browser2.RenderToTexture(_texture2);
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Thread.Sleep(32);
|
Thread.Sleep(32);
|
||||||
|
|||||||
Reference in New Issue
Block a user