Render 3D scene on locked system
I have written a Direct3D 9 based rendering engine in c# using SlimDX. In a new project I now need to distribute pictures of a loaded 3d scene using a webservice. The problem is that in order to r开发者_Python百科ender anything at all I need a Direct3d device. Is there any way to create a direct3d device without a user being logged in to the system and the desktop not being locked?
If that is not possible, does anyone know of a workaround? In the end I need either an executable which can be run from the task planner using some local user account or a service, which periodically renders pictures of the scene from certain viewpoints.
The engine is split into two parts: the engine itself and the renderer. So if there's no other way then I could also implement a new renderer using opengl or any other technology which allows for rendering without having a visible form.
Edit:
What I have so far is this:
protected override void OnContinue() {
base.OnContinue();
NativeFunctions.SafeWindowStationHandle hwinsta = NativeFunctions.WindowStation.OpenWindowStation(
"WinSta0",
true,
NativeFunctions.AccessMask.WINSTA_ALL_ACCESS);
if(hwinsta == null || hwinsta.IsClosed || hwinsta.IsInvalid)
Marshal.ThrowExceptionForHR(Marshal.GetLastWin32Error());
if(NativeFunctions.WindowStation.SetProcessWindowStation(hwinsta.DangerousGetHandle())) {
NativeFunctions.SafeDesktopHandle ptrDesktop = NativeFunctions.WindowStation.OpenInputDesktop(
0,
true,
NativeFunctions.AccessMask.DESKTOP_CREATEWINDOW);
if(ptrDesktop.IsClosed || ptrDesktop.IsInvalid)
return;
if(!NativeFunctions.WindowStation.SetThreadDesktop(ptrDesktop.DangerousGetHandle()))
return;
Log log = Logger.Instance.CreateLog("DXService", true, true, false);
log.LogMessage("Desktop set, creating D3D-Object.", LOGMESSAGELEVEL.CRITICAL, true);
Direct3D direct3D = new Direct3D();
log.LogMessage("Direct3D object created, creating device.", LOGMESSAGELEVEL.CRITICAL, true);
if(direct3D.AdapterCount == 0) {
log.LogMessage("FATAL: direct3D.AdapterCount == 0");
}
}
}
This is part of a minimal WindowsService. I put the important code into the OnContinue function because it's easier to debug than the startup code. I gave this services the right to interact with the active desktop. when I run the service as a local systemaccount getting the desktop and windowstation works but the number of GraphicsAdapters still is 0, when I run the service using a dedicated user account then I can't even open the WindowStation. Is there anything else I can try or which I'm doing wrong? I am testing this on a Windows 7 machine, while I am logged in since debugging becomes very difficult otherwise. Might this be a problem?
Thanks
Back in the days of XP I worked on a project which successfully invoked Direct3D hardware rendering from a service on a machine with no-one logged into the console. I completely forget the (ingenious) details, but it required some use of the "Window Station and Desktop Functions" API to somehow get hold of a usable HWND. Newer/server OS are likely completely different anyway with all the new security stuff though.
I'd be surprised if OpenGL worked any better than Direct3D in this area, although it might be worth a try. Other things you might consider:
- NVidia seem to be very much developing their GPGPU/CUDA stuff with headless servers in mind. It just works. It does mean completely reimplementing your stuff on a non-graphics API though.
- Microsoft's RemoteFX (Server2008R2 and Win7) seems to making it easier for VMs to gain access to server GPUs. (Perversely, your easiest option might just be to run your renderer in a VM.)
In the case of OpenGL using a PBuffer context might work to get GPU acceleration on even a locked desktop; however this strongly depends on the driver, which may set the PBuffer to permanently damaged while locked, so YMMV. I'd give it a shot.
精彩评论