我有一个用c ++编写的OpenGL库,它是使用C ++ / CLI适配器从C#应用程序中使用的。我的问题是如果应用程序用于具有Nvidia Optimus技术的笔记本电脑上,应用程序将不会使用硬件加速并失败。
我尝试使用Nvidias文档http://developer.download.nvidia.com/devzone/devcenter/gamegraphics/files/OptimusRenderingPolicies.pdf中的信息 关于将libs链接到我的C ++ -dll并从我的OpenGL库中导出NvOptimusEnablement但是失败了。 我想我必须对.exe执行一些操作,而不是使用.dll链接到.exe
对我们来说,使用配置文件不是一个好选择,因为我们需要确保使用nvidia硬件。
C#应用程序是否有某种方式可以强制Optimus使用Nvidia芯片组而不是集成的Intel芯片组?
答案 0 :(得分:3)
我尝试了the swine的两个选项,但都没有自己动手。我发现我需要尝试调用导入的函数。
$sql = "INSERT INTO membre (Name, Age) VALUES (\'$Name\', \'$Age\')";
OR
$sql = "INSERT INTO membre (Name, Age) VALUES ('".$Name."', '".$Age."')";
然后在我的应用启动中:
using System.Runtime.InteropServices;
class OptimusEnabler
{
[DllImport("nvapi.dll")]
public static extern int NvAPI_Initialize();
};
在nVidia Optimus系统上,我得到try
{
///Ignore any System.EntryPointNotFoundException
///or System.DllNotFoundException exceptions here
OptimusEnabler.NvAPI_Initialize();
}
catch
{ }
,但它仍然可以使应用程序使用nVidia硬件。在带有ATI卡的系统上测试时,我得到了System.EntryPointNotFoundException
。无论哪种方式,尝试调用此方法并忽略任何异常似乎都可以正常工作。
答案 1 :(得分:3)
工作解决方案。实际上所有那些已经提到的,但我花了一些时间来了解如何让它工作......
fonts
重要 - 在创建任何窗口之前调用[System.Runtime.InteropServices.DllImport("nvapi64.dll", EntryPoint = "fake")]
static extern int LoadNvApi64();
[System.Runtime.InteropServices.DllImport("nvapi.dll", EntryPoint = "fake")]
static extern int LoadNvApi32();
private void InitializeDedicatedGraphics()
{
try
{
if (Environment.Is64BitProcess)
LoadNvApi64();
else
LoadNvApi32();
}
catch { } // will always fail since 'fake' entry point doesn't exists
}
答案 2 :(得分:1)
如果您的软件在英特尔上失败,那么您将无法在50%的笔记本电脑上运行它。所以我建议修改它。
比起说,您可以通过代码完美地创建配置文件。只需使用NvAPI即可。 这段代码确实如此,但要注意,您可能不应该使用全局配置文件并创建自己的配置文件:
NvAPI_Status status;
// (0) Initialize NVAPI. This must be done first of all
status = NvAPI_Initialize();
if (status != NVAPI_OK)
PrintError(status, __LINE__);
// (1) Create the session handle to access driver settings
NvDRSSessionHandle hSession = 0;
status = NvAPI_DRS_CreateSession(&hSession);
if (status != NVAPI_OK)
PrintError(status, __LINE__);
// (2) load all the system settings into the session
status = NvAPI_DRS_LoadSettings(hSession);
if (status != NVAPI_OK)
PrintError(status, __LINE__);
// (3) Obtain the Base profile. Any setting needs to be inside
// a profile, putting a setting on the Base Profile enforces it
// for all the processes on the system
NvDRSProfileHandle hProfile = 0;
status = NvAPI_DRS_GetBaseProfile(hSession, &hProfile);
if (status != NVAPI_OK)
PrintError(status, __LINE__);
NVDRS_SETTING drsSetting1 = {0};
drsSetting1.version = NVDRS_SETTING_VER;
drsSetting1.settingId = SHIM_MCCOMPAT_ID;
drsSetting1.settingType = NVDRS_DWORD_TYPE;
NVDRS_SETTING drsSetting2 = {0};
drsSetting2.version = NVDRS_SETTING_VER;
drsSetting2.settingId = SHIM_RENDERING_MODE_ID;
drsSetting2.settingType = NVDRS_DWORD_TYPE;
NVDRS_SETTING drsSetting3 = {0};
drsSetting3.version = NVDRS_SETTING_VER;
drsSetting3.settingId = SHIM_RENDERING_OPTIONS_ID;
drsSetting3.settingType = NVDRS_DWORD_TYPE;
if( ForceIntegrated ){
drsSetting1.u32CurrentValue = SHIM_MCCOMPAT_INTEGRATED;
drsSetting2.u32CurrentValue = SHIM_RENDERING_MODE_INTEGRATED;
drsSetting3.u32CurrentValue = SHIM_RENDERING_OPTIONS_DEFAULT_RENDERING_MODE | SHIM_RENDERING_OPTIONS_IGPU_TRANSCODING;
}else{
drsSetting1.u32CurrentValue = SHIM_MCCOMPAT_ENABLE;
drsSetting2.u32CurrentValue = SHIM_RENDERING_MODE_ENABLE;
drsSetting3.u32CurrentValue = SHIM_RENDERING_OPTIONS_DEFAULT_RENDERING_MODE;
}
status = NvAPI_DRS_SetSetting(hSession, hProfile, &drsSetting1);
if (status != NVAPI_OK)
PrintError(status, __LINE__);
status = NvAPI_DRS_SetSetting(hSession, hProfile, &drsSetting2);
if (status != NVAPI_OK)
PrintError(status, __LINE__);
status = NvAPI_DRS_SetSetting(hSession, hProfile, &drsSetting3);
if (status != NVAPI_OK)
PrintError(status, __LINE__);
// (5) Now we apply (or save) our changes to the system
status = NvAPI_DRS_SaveSettings(hSession);
if (status != NVAPI_OK)
PrintError(status, __LINE__);
// (6) We clean up. This is analogous to doing a free()
NvAPI_DRS_DestroySession(hSession);
hSession = 0;
启动时,测试您的个人资料是否存在。如果没有,创建它(你可能也必须重新启动)。 NvAPI是一个静态库,可以在非NVIDIA硬件上正常返回错误代码,因此您可以安全地发送它。
编辑:看起来有一种更简单的方法。来自GLFW 3源代码:
// Applications exporting this symbol with this value will be automatically
// directed to the high-performance GPU on nVidia Optimus systems
//
GLFWAPI DWORD NvOptimusEnablement = 0x00000001;
答案 3 :(得分:1)
我的解决方案基于导出的功能NvOptimusEnablement和AmdPowerXpressRequestHighPerformance,在没有DllExport(没有NuGet软件包UnmanagedExports)的情况下,可在NVidia和AMD上运行:
在VS2019上,上述的UnmanagedExports软件包似乎无法正常工作。我找不到另一个提供DllExport功能的.NET框架工作包。这就是为什么我在Writing IL code on Visual Studio和IL Support的大力帮助下使用直接MSIL代码开发了自己的解决方案的原因。
要遵循的步骤:
要向.csproj文件(用于exe的.csproj,不适用于任何dll),请添加以下部分,以便直接使用MSIL代码(通常可以将其放在任何位置,即
<PropertyGroup>
<CoreCompileDependsOn>
HideILFromCoreCompile;
$(CoreCompileDependsOn);
</CoreCompileDependsOn>
<CompileDependsOn>
HideILFromCompile;
$(CompileDependsOn);
InitializeIL;
CoreDecompile;
CoreCompileIL;
</CompileDependsOn>
</PropertyGroup>
<Target Name="HideILFromCoreCompile">
<ItemGroup>
<Compile Remove="@(Compile)" Condition="'%(Extension)'=='.il'" />
</ItemGroup>
</Target>
<Target Name="HideILFromCompile">
<ItemGroup>
<IL Include="@(Compile)" Condition="'%(Extension)'=='.il'" />
<Compile Remove="@(Compile)" Condition="'%(Extension)'=='.il'" />
</ItemGroup>
</Target>
<Target Name="InitializeIL">
<PropertyGroup>
<ILFile>@(IntermediateAssembly->'%(RootDir)%(Directory)%(Filename).il', ' ')</ILFile>
<ILResourceFile>@(IntermediateAssembly->'%(RootDir)%(Directory)%(Filename).res', ' ')</ILResourceFile>
</PropertyGroup>
</Target>
<Target Name="CoreDecompile" Inputs="@(IntermediateAssembly)" Outputs="$(ILFile)" Condition=" Exists ( @(IntermediateAssembly) ) ">
<GetFrameworkSdkPath>
<Output TaskParameter="Path" PropertyName="FrameworkSdkPath" />
</GetFrameworkSdkPath>
<PropertyGroup>
<ILDasm>"$(FrameworkSdkPath)bin\ildasm.exe" /nobar /linenum /output:"$(ILFile)" @(IntermediateAssembly->'"%(FullPath)"', ' ')</ILDasm>
</PropertyGroup>
<PropertyGroup Condition=" Exists ( '$(FrameworkSdkPath)bin\NETFX 4.0 Tools\ildasm.exe' ) ">
<ILDasm>"$(FrameworkSdkPath)bin\NETFX 4.0 Tools\ildasm.exe" /nobar /linenum /output:"$(ILFile)" @(IntermediateAssembly->'"%(FullPath)"', ' ')</ILDasm>
</PropertyGroup>
<PropertyGroup Condition=" Exists ( '$(FrameworkSdkPath)bin\NETFX 4.5.1 Tools\ildasm.exe' ) ">
<ILDasm>"$(FrameworkSdkPath)bin\NETFX 4.5.1 Tools\ildasm.exe" /nobar /linenum /output:"$(ILFile)" @(IntermediateAssembly->'"%(FullPath)"', ' ')</ILDasm>
</PropertyGroup>
<PropertyGroup Condition=" Exists ( '$(FrameworkSdkPath)bin\NETFX 4.6 Tools\ildasm.exe' ) ">
<ILDasm>"$(FrameworkSdkPath)bin\NETFX 4.6 Tools\ildasm.exe" /nobar /linenum /output:"$(ILFile)" @(IntermediateAssembly->'"%(FullPath)"', ' ')</ILDasm>
</PropertyGroup>
<PropertyGroup Condition=" Exists ( '$(FrameworkSdkPath)bin\NETFX 4.6.1 Tools\ildasm.exe' ) ">
<ILDasm>"$(FrameworkSdkPath)bin\NETFX 4.6.1 Tools\ildasm.exe" /nobar /linenum /output:"$(ILFile)" @(IntermediateAssembly->'"%(FullPath)"', ' ')</ILDasm>
</PropertyGroup>
<PropertyGroup Condition=" Exists ( '$(FrameworkSdkPath)bin\NETFX 4.6.2 Tools\ildasm.exe' ) ">
<ILDasm>"$(FrameworkSdkPath)bin\NETFX 4.6.2 Tools\ildasm.exe" /nobar /linenum /output:"$(ILFile)" @(IntermediateAssembly->'"%(FullPath)"', ' ')</ILDasm>
</PropertyGroup>
<Exec Command="$(ILDasm)" />
<ItemGroup>
<FileWrites Include="$(ILFile)" />
<FileWrites Include="$(ILResourceFile)" />
</ItemGroup>
<PropertyGroup>
<ILSource>$([System.IO.File]::ReadAllText($(ILFile)))</ILSource>
<Replacement>// method ${method} forwardref removed for IL import</Replacement>
<Pattern>\.method [^{}]+ cil managed forwardref[^}]+} // end of method (?<method>[^ \r\t\n]+)</Pattern>
<ILSource>$([System.Text.RegularExpressions.Regex]::Replace($(ILSource), $(Pattern), $(Replacement)))</ILSource>
<Pattern>\.method [^{}]+ cil managed[^\a]+"extern was not given a DllImport attribute"[^}]+} // end of method (?<method>[^ \r\t\n]+)</Pattern>
<ILSource>$([System.Text.RegularExpressions.Regex]::Replace($(ILSource), $(Pattern), $(Replacement)))</ILSource>
</PropertyGroup>
<WriteLinesToFile File="$(ILFile)" Lines="$(ILSource)" Overwrite="true" />
<PropertyGroup>
<ILSource />
</PropertyGroup>
<Delete Files="@(IntermediateAssembly)" />
</Target>
<Target Name="CoreCompileIL" Inputs="@(IL)" Outputs="@(IntermediateAssembly)">
<GetFrameworkPath>
<Output TaskParameter="Path" PropertyName="FrameworkPath" />
</GetFrameworkPath>
<PropertyGroup>
<ILAsm>"$(FrameworkPath)\ilasm.exe" /nologo /quiet /output:@(IntermediateAssembly->'"%(FullPath)"', ' ')</ILAsm>
</PropertyGroup>
<PropertyGroup Condition=" '$(FileAlignment)' != '' ">
<ILAsm>$(ILAsm) /alignment=$(FileAlignment)</ILAsm>
</PropertyGroup>
<PropertyGroup Condition=" '$(BaseAddress)' != '' ">
<ILAsm>$(ILAsm) /base=$(BaseAddress)</ILAsm>
</PropertyGroup>
<PropertyGroup Condition=" '$(OutputType)' == 'Library' ">
<ILAsm>$(ILAsm) /dll</ILAsm>
</PropertyGroup>
<PropertyGroup Condition=" '$(DebugType)' == 'pdbonly' ">
<ILAsm>$(ILAsm) /pdb</ILAsm>
</PropertyGroup>
<PropertyGroup Condition=" '$(DebugType)' == 'full' ">
<ILAsm>$(ILAsm) /debug</ILAsm>
</PropertyGroup>
<PropertyGroup Condition=" '$(Optimize)' == 'true' ">
<ILAsm>$(ILAsm) /optimize</ILAsm>
</PropertyGroup>
<PropertyGroup Condition=" '$(Platform)' == 'x64' ">
<ILAsm>$(ILAsm) /pe64 /x64</ILAsm>
</PropertyGroup>
<PropertyGroup Condition=" '$(Platform)' == 'Itanium' ">
<ILAsm>$(ILAsm) /pe64 /itanium</ILAsm>
</PropertyGroup>
<PropertyGroup Condition=" '$(AssemblyOriginatorKeyFile)' != '' ">
<ILAsm>$(ILAsm) /key:"$(AssemblyOriginatorKeyFile)"</ILAsm>
</PropertyGroup>
<PropertyGroup Condition=" Exists ( '$(ILResourceFile)' ) ">
<ILAsm>$(ILAsm) /resource:"$(ILResourceFile)"</ILAsm>
</PropertyGroup>
<PropertyGroup Condition=" Exists ( '$(ILFile)' ) ">
<ILAsm>$(ILAsm) "$(ILFile)"</ILAsm>
</PropertyGroup>
<Exec Command="$(ILAsm) @(IL->'"%(FullPath)"', ' ')" />
<ItemGroup>
<FileWrites Include="@(IntermediateAssembly->'%(RootDir)%(Directory)DesignTimeResolveAssemblyReferencesInput.cache', ' ')" />
</ItemGroup>
<Touch Files="$(ILFile)" />
</Target>
将以下代码粘贴到该文件中(而不是“ WindowsApplication1”,您可以输入名称空间):
.class public WindowsApplication1.ForceDedicatedGraphicCard
{
.method public static int32 NvOptimusEnablement() cil managed
{
.export [1]
ldc.i4.1
ret
}
.method public static uint32 AmdPowerXpressRequestHighPerformance() cil managed
{
.export [2]
ldc.i4.1
ret
}
}
检查是否使用dumpbin.exe
导出了功能dumpbin.exe /exports your_project.exe
答案 4 :(得分:0)
从文件中看起来似乎很简单。你有多种选择如何做到这一点。不幸的是, exe 需要这样做,而不是dll。根据{{3}},可能会执行以下操作:
class OptimusEnabler {
[DllExport("NvOptimusEnablement")]
public static int NvOptimusEnablement = 1;
};
然后需要将其包含在您的C ++库接口中,以便任何使用它的C#应用程序都将被强制导出它。或者,您可以尝试链接nvapi.dll
:
class OptimusEnabler {
[DllImport("nvapi.dll")]
public static extern int NvAPI_Initialize();
};
根据该文件,这也足以将您的应用程序识别为启用NV。甚至不需要调用导入的函数。