|
public Bitmap GetMirrorImage(EVREye eye = EVREye.Eye_Left) |
|
{ |
|
var srvPtr = IntPtr.Zero; |
|
|
|
var result = OpenVR.Compositor.GetMirrorTextureD3D11(eye, device.NativePointer, ref srvPtr); |
|
if (result != EVRCompositorError.None) |
|
throw new OpenVRSystemException<EVRCompositorError>("Failed to get mirror texture from OpenVR", result); |
|
|
|
var srv = new ShaderResourceView(srvPtr); |
|
var tex = srv.Resource.QueryInterface<Texture2D>(); |
|
var texDesc = tex.Description; |
|
|
|
var bitmap = new Bitmap(texDesc.Width, texDesc.Height); |
|
var boundsRect = new Rectangle(0, 0, texDesc.Width, texDesc.Height); |
|
|
|
using(var cpuTex = new Texture2D(device, new Texture2DDescription |
|
{ |
|
CpuAccessFlags = CpuAccessFlags.Read, |
|
BindFlags = BindFlags.None, |
|
Format = texDesc.Format, |
|
Width = texDesc.Width, |
|
Height = texDesc.Height, |
|
OptionFlags = ResourceOptionFlags.None, |
|
MipLevels = 1, |
|
ArraySize = 1, |
|
SampleDescription = { Count = 1, Quality = 0 }, |
|
Usage = ResourceUsage.Staging |
|
})) |
|
{ |
|
// Copy texture to RAM so CPU can read from it |
|
device.ImmediateContext.CopyResource(tex, cpuTex); |
|
OpenVR.Compositor.ReleaseMirrorTextureD3D11(srvPtr); |
|
|
|
var mapSource = device.ImmediateContext.MapSubresource(cpuTex, 0, MapMode.Read, MapFlags.None); |
|
var mapDest = bitmap.LockBits(boundsRect, ImageLockMode.WriteOnly, bitmap.PixelFormat); |
|
var sourcePtr = mapSource.DataPointer; |
|
var destPtr = mapDest.Scan0; |
|
|
|
for (int y = 0; y < texDesc.Height; y++) |
|
{ |
|
Utilities.CopyMemory(destPtr, sourcePtr, texDesc.Width * 4); |
|
sourcePtr = IntPtr.Add(sourcePtr, mapSource.RowPitch); |
|
destPtr = IntPtr.Add(destPtr, mapDest.Stride); |
|
} |
|
|
|
bitmap.UnlockBits(mapDest); |
|
device.ImmediateContext.UnmapSubresource(cpuTex, 0); |
|
} |
|
|
|
FlipChannels(ref bitmap); |
|
return bitmap; |
|
} |
DirectXCompositor.GetMirrorImageis really slow right now (~15ms per call on average), mostly because there's lots of copying and manipulation going on. We should explore different ways of improving performance, such as:async(would OpenVR be happy with that? If not, we could call the OpenVR API on the main thread, then do the rest of the work on a different thread)FlipChannelsafter the image is copied over, can we do this while copying the memory initially?Texture2D->Bitmapcopying more efficient?I don't work with DirectX much (or graphics APIs in general) so there could be something I'm missing. Any input is appreciated :)
For reference, here's the method:
OVRSharp/OVRSharp.Graphics.DirectX/DirectXCompositor.cs
Lines 52 to 103 in f75f356