Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Explore ways to improve performance of GetMirrorImage DirectX implementation #11

Open
tjhorner opened this issue Jul 11, 2021 · 0 comments
Labels
enhancement New feature or request

Comments

@tjhorner
Copy link
Member

tjhorner commented Jul 11, 2021

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

@tjhorner tjhorner added the enhancement New feature or request label Jul 11, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

1 participant