How to give an option to select graphics adapter in a DirectX 11 application? - c++

I think I know how it should work - only it does not. I have a lenovo laptop with a 860m and an intel integrated card.
I can run my application from outside with both gpu, and everything works fine: the selected gpu will be the adapter with index 0, it has the laptop screen as output, etc.
However if I try to use the adapter with index 1 (if I run the app normally, that is the nvidia, if I run it with the nvidia gpu, that is the intel), IDXGIOutput::EnumOutputs does not find anything, so I can't configure the display settings properly.
I was thinking about simply skipping the configuration, or using the output from the other adapter - but then there is no way to filter out adapters without real output - e.g. my pc has an integrated card too, but it does not have a monitor physically connected, so using that should not be possible.
I also tried to find what exactly the "Run with graphical processor" context menu button does, but I could not find anything.
Goal is to give the user the ability to select adapter inside the application, his/her choices is saved to a config file, and would be used after restart - but I can't find the way to filter the possible adapters.

You likely have a 'heterogenous adapter' system (a.k.a. NVIDIA Optimus or AMD PowerXPress). These solutions have the driver manipulate the default adapter and the device enumeration to control which card is used. You really don't have any programmatic control over this, but you can inject something into your Win32 'classic' desktop application which will encourage the driver to select the discrete part:
// Indicates to hybrid graphics systems to prefer the discrete part by default
extern "C"
{
__declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001;
__declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1;
}
UPDATE With Windows 10 April 2018 Update (17134) or later, you can use the DXGI 1.6 interface EnumAdapterByGpuPreference. See GitHub for some example usage.

Related

DirectX11 Desktop duplication not working with NVIDIA

I'm trying too use DirectX desktop duplication API.
I tried running exmaples from
http://www.codeproject.com/Tips/1116253/Desktop-Screen-Capture-on-Windows-via-Windows-Desk
And from
https://code.msdn.microsoft.com/windowsdesktop/Desktop-Duplication-Sample-da4c696a
Both of these are examples of screen capture using DXGI.
I have NVIDIA GeForce GTX 1060 with Windows 10 Pro on the machine. It has Intelâ„¢ Core i7-6700HQ processor.
These examples work perfectly fine when NVIDIA Control Panel > 3D Settings is selected to Auto select processor.
However if I set the setting manually to NVIDIA Graphics Card the samples stop working.
Error occurs at the following line.
//IDXGIOutput1* DxgiOutput1
hr = DxgiOutput1->DuplicateOutput(m_Device, &m_DeskDupl);
Error in hr(HRESULT) is DXGI_ERROR_UNSUPPORTED 0x887A0004
I'm new to DirectX and I don't know the issue here, is DirectX desktop duplication not supported on NVIDIA ?
If that's the case then is there a way to select a particular processor at the start of program so that program can run with any settings ?
#Edit
After looking around I asked the developer (Evgeny Pereguda) of the second sample project on codeproject.com
Here's a link to the discussion
https://www.codeproject.com/Tips/1116253/Desktop-Screen-Capture-on-Windows-via-Windows-Desk?msg=5319978#xx5319978xx
Posting the screenshot of the discussion on codeproject.com in case original link goes down
I also found an answer on stackoverflow which unequivocally suggested that it could not be done with the desktop duplication API referring to support ticket at microsoft's support site https://support.microsoft.com/en-us/help/3019314/error-generated-when-desktop-duplication-api-capable-application-is-ru
Quote from the ticket
This issue occurs because the DDA does not support being run against
the discrete GPU on a Microsoft Hybrid system. By design, the call
fails together with error code DXGI_ERROR_UNSUPPORTED in such a
scenario.
However there are some applications which are efficiently duplicating desktop on windows in both modes (integrated graphics and discrete) on my machine. (https://www.youtube.com/watch?v=bjE6qXd6Itw)
I have looked into the installation folder of the Virtual Desktop on my machine and can see following DLLs of interest
SharpDX.D3DCompiler.dll
SharpDX.Direct2D1.dll
SharpDX.Direct3D10.dll
SharpDX.Direct3D11.dll
SharpDX.Direct3D9.dll
SharpDX.dll
SharpDX.DXGI.dll
SharpDX.Mathematics.dll
Its probably an indication that this application is using DXGI to duplicate desktop, or may be the application is capable of selecting a specific processor before it starts.
Anyway the question remains, is there any other efficient method of duplicating desktop in both modes?
The likely cause is certain internal limitation for Desktop Duplication API, described in Error generated when Desktop Duplication API-capable application is run against discrete GPU:
... when the application tries to duplicate the desktop image against the discrete GPU on a Microsoft Hybrid system, the application may not run correctly, or it may generate one of the following errors:
Failed to create windows swapchain with 0x80070005
CDesktopCaptureDWM: IDXGIOutput1::DuplicateOutput failed: 0x887a0004
The article does not suggest any other workaround except use of a different GPU (without more specific detail as for whether it is at all achievable programmatically):
To work around this issue, run the application on the integrated GPU instead of on the discrete GPU on a Microsoft Hybrid system.
Microsoft introduced a registry value that can be set programmatically to control which GPU an application runs on. Full answer here.

Intel Integrated Graphics misidentification (DXGI)

I'm filling a window with a blank swap chain that's being handled by DirectX 12. While fooling a round a bit with Explicit Multi-Adapter, I came across this weird behaviour...
As shown in pretty much all DX12 demo code in existence so far, I loop through all DXGI adapters that I get using IDXGIFactory4::EnumAdapters1() to find the most suitable (or in my case every) adapter at D3D_FEATURE_LEVEL_11_0 or higher. And as shown in the demos, I discard all adapters that have the DXGI_ADAPTER_FLAG_SOFTWARE like this:
if ((adapterDesc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE) != FALSE)
continue; // Check the next adapter.
In my implementation I then dump all compatible adapters into a std::vector to be used later.
If I use a breakpoint to check how everything looks at runtime, I notice my adapter list only contains one adapter after the loop has exited, which is not what I would expect, as I have both an NVIDIA GeForce GT 650M and an Intel HD Graphics 4000.
By breaking during the loop and checking the DXGI_ADAPTER_DESC2 structure for each adapter, I find that the one I get is indeed the GT 650M, so that means my integrated graphics is identifying itself as a software adapter.
This is plausible on its own, but if you look at a picture of an Ivy Bridge die (which is what I have) you see a big area cordoned off as "Processor Graphics", which Intel themselves define like this: "Processor graphics refer to graphics that are physically in the processor package or integrated into the processor silicon." That just screams "hardware adapter" at me.
If I remove the above code block I do indeed get two adapters in my list, but the second one identifies itself as "Microsoft Basic Render Driver" and gives a vendor ID of 0x1414, while Google says that Intel usually returns 0x8086 as its ID. This list doesn't even mention the owner of 0x1414.
And, to make things even more confusing, if I check the Information Center in my Intel HD Graphics Control Panel it says it has a vendor ID of 0x8086!
Before anyone asks: Yes, my drivers should be up-to-date; I updated them as soon as I noticed this. Strangely though, DxDiag gives me an incorrect driver date for the integrated graphics, but does the same (though slightly closer to the truth) for the GT 650M. The discrete GPU driver is of WDDM 2.0, while the integrated graphics driver is of WDDM 1.3, which might be relevant, because I think it should be of 2.0 too. (Might the update have failed?)
The primary reason for the if (adapterDesc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE) filter is to avoid selecting the Microsoft Basic Render Driver. This uses the WARP11 software device which does not support DirectX 12.
WARP11 is supported in all versions of Windows with DirectX 11. WARP12 is currently a developer only device (i.e. "Graphics Tools" optional feature-on-demand is installed).
It's probably a bug if your discrete part is returning true for this flag. It might be a bug in your code, a driver bug, or some strange side-effect of Optimus-style selection. WARP / MBR is really the only thing that is expected to return DXGI_ADAPTER_FLAG_SOFTWARE.
You can also exclude MBR via a if ( ( adapterDesc.VendorId == 0x1414 ) && ( adapterDesc.DeviceId == 0x8c ) ) test for well-known VendorID/DeviceID, but I suggest digging your code to understand why you are incorrectly getting DXGI_ADAPTER_FLAG_SOFTWARE returned for hardware devices.
See Anatomy of Direct3D 11 Create Device

Programmatically selecting integrated graphics in nVidia Optimus

There are many questions and answers about how to select nVidia discrete adapter on runtime on Windows platform. The easiest way is to export a NvOptimusEnablement variable like this:
extern "C" _declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001;
I have the opposite requirement. I need to set the Integrated graphics in runtime for my application, no matter what is the Preferred graphic processor in NVIDIA control panel. This variable is not suitable for this. How can I make this?
The code under sop - setoptimusprofile registers an application profile so the driver automatically selects the discrete card for the specified application. Maybe you can change it so that it uses the integrated one?

Forcing Machine to Use Dedicated Graphics Card?

I am part of a team developing an application using C++ with SDL and OpenGL.
On laptops when the application is ran the dedicated graphics card is not used and the GL context fails to create because the integrated graphics card does not support the version of GL we want.
I have a feeling that this problem is specific to the laptop in question and not something we can solve through code. But, if anyone knows if there is a solution that'd be great.
The easiest way from C++ to ensure that the dedicated graphics card is used instead of chipset switchable graphics under Windows is to export the following symbols (MSVC sample code):
Enable dedicated graphics for NVIDIA:
extern "C"
{
__declspec(dllexport) unsigned long NvOptimusEnablement = 0x00000001;
}
Enable dedicated graphics for AMD Radeon:
extern "C"
{
__declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1;
}
Caveat: If the user has created a profile for the application to use integrated chipset, then these will not work.
I am unsure if this would work similarly under Linux / MacOS (unlikely).
Does it use NVidia dedicated graphics? AFAIK, the process of automatically switching from integrated to dedicated is based on application profiles. Your application is not in the driver's list of known 3D applications, and therefore the user has to manually switch to the dedicated GPU.
Try changing the executable name of your application to something the driver looks for. For example "Doom3.exe". If that works, then you've found your problem.
If that didn't help, try following the instructions on how to make the driver insert your application in its list of 3D apps:
https://nvidia.custhelp.com/app/answers/detail/a_id/2615/~/how-do-i-customize-optimus-profiles-and-settings
But the above is only for verifying if this is indeed your problem. For an actual solution to this, you should check with the graphics drivers vendors (AMD and NVidia) on the best way to insert a profile for your application into their lists. NVidia provides NVAPI and AMD has ADL and AGS. They're definitely worth a study.

I have two GPUs, how can I just let one to do certain CUDA task?

New to CUDA, but have some time spending on computing, and I have geforces at home and tesla (same generation) in the office.
At home I have two gpus installed in the same computer, one is GK110 (compute capability 3.5), the other is GF110 (compute capability 2.0), I perfer to use GK110 for computation task ONLY and GF110 for display UNLESS I tell it to do computation, is there a way to do this through driver setting or I still need to rewrite some of my codes?
Also, if I understand correctly, if the display port of GK110 is not being connected, then the annoying windows timeout detection will not try to reset it even if the computation time is very long?
Btw my CUDA codes are compiled with both compute_35 and compute20, so the codes can be run on both GPUs, however I plan to use features that being exclusive to GK110 so the codes in the future may not being able to run on GF110 at all, and the OS is windows 7.
With a GeForce GTX Titan (or any GeForce product) on Windows, I don't believe there is a way to prevent the GPU from appearing in the system in WDDM mode, which means that windows will build a display driver stack on it, even if the card has no physical display attached to it. So you may be stuck with the windows TDR mechanism. You could try experimenting with it to confirm that. (The windows TDR behavior can be modified via registry hacking).
Regarding steering CUDA tasks to the GTX Titan, the display driver control panel should have a selectable setting for this. It may be in the "Manage 3D settings" area or some other area depending on which driver you have. When you find the appropriate settings area, there will be a selection entitled something like CUDA - GPUs which will probably be set to "All". If you change the "Global Presets" selection to "Base Profile" you should be able to change this CUDA-GPUs setting. Clicking on it should give you a selection of "All" or a set of checkboxes for each GPU detected. If you uncheck the GF110 device and check the GK110 device, then CUDA programs that do not select a particular GPU via cudaSetDevice() should be steered to the GK110 device based on this checkbox selection. You may want to experiment with this as well to confirm.
Other than that, as mentioned in the comments, using a programmatic method, you can always query device properties and then select the device that reports itself as a cc3.5 device.