Skip to content

Explore ways to improve performance of GetMirrorImage DirectX implementation #11

@tjhorner

Description

@tjhorner

DirectXCompositor.GetMirrorImage is 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:

  • Minimize copying from GPU to RAM (at least once is necessary, though)
  • See if we can execute this on a different thread and make the method 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)
  • Instead of using FlipChannels after the image is copied over, can we do this while copying the memory initially?
  • Can we make the Texture2D -> Bitmap copying 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:

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;
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions