7

I want my application to always run using the real gpu on nVidia Optimus laptops.

From "Enabling High Performance Graphics Rendering on Optimus Systems", (http://developer.download.nvidia.com/devzone/devcenter/gamegraphics/files/OptimusRenderingPolicies.pdf):

Global Variable NvOptimusEnablement (new in Driver Release 302) Starting with the Release 302 drivers, application developers can direct the Optimus driver at runtime to use the High Performance Graphics to render any application–even those applications for which there is no existing application profile. They can do this by exporting a global variable named NvOptimusEnablement. The Optimus driver looks for the existence and value of the export. Only the LSB of the DWORD matters at this time. A value of 0x00000001 indicates that rendering should be performed using High Performance Graphics. A value of 0x00000000 indicates that this method should be ignored. Example Usage:

extern "C" {   _declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001; }

The problem is that I want to do this using Delphi. From what I've read Delphi does not support export of variables even though some hacks exists. I did try a few of them but couldn't make it work.

In the same nvidia document I read that forcing the proper GPU can be accomplished via linking statically to one of a handful listed dlls. But I don't want to link to dlls I'm not using. (Why the opengl.dll is not one of them is beyond me.) A simple exported variable seems much cleaner.

DelphiDabber
  • 295
  • 2
  • 13

2 Answers2

4

From what I've read Delphi does not support export of variables.

That statement is incorrect. Here's the simplest example that shows how to export a global variable from a Delphi DLL:

library GlobalVarExport;

uses
  Windows;

var
  NvOptimusEnablement: DWORD;

exports
  NvOptimusEnablement;

begin
  NvOptimusEnablement := 1;
end.

I think your problem is that you wrote it like this:

library GlobalVarExport;

uses
  Windows;

var
  NvOptimusEnablement: DWORD=1;

exports
  NvOptimusEnablement;

begin
end.

And that fails to compile with this error:

E2276 Identifier 'NvOptimusEnablement' cannot be exported

I don't understand why the compiler doesn't like the second version. It's probably a bug. But the workaround in the first version is just fine.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • I've managed to place a var in the OpenGL wrapper unit and in the initilization section I asm MOV $1 into the variable. I read somewhere that otherwise it would be ignored by the compiler. Running PE Explorer there is an export with the correct name and the value 1. Unfortunately I don't have an optimus laptop in front of me so I can't test this until tomorrow. But the Delphi part of my problem seems to be solved. – DelphiDabber Mar 13 '13 at 10:21
  • 1
    You don't need to use asm at all. The compiler won't optimise out writes to global variables. – David Heffernan Mar 13 '13 at 10:25
  • Yes, the export is correct with the asm replaced by `NvOptimusEnablement := $1;` – DelphiDabber Mar 13 '13 at 10:31
  • It seems that the OP was incorrect in his assertion that Delphi can't export variables? – Warren P Mar 13 '13 at 20:23
  • 1
    @WarrenP That's correct. It's really a dupe. But the twist is that an initialised variable cannot be exported for some reason unknown to me. – David Heffernan Mar 13 '13 at 20:24
0

I'm not a Delphi expert, but AFAIK it is possible to link to static libraries implemented in C from Delphi. So I'd simply create a small stub library, just providing this export, which is statically linked into your Delphi program. This adds the very export you need.

datenwolf
  • 159,371
  • 13
  • 185
  • 298
  • No, it is not possible to link static libraries. – David Heffernan Mar 12 '13 at 22:12
  • @DavidHeffernan: Technically this is something that should be applicable to the PE binary in a postprocessing step. The GNU binutils contain a program called "objcopy" that's kind of the swiss army knife when it comes to binary manipulation. You could use objcopy to copy a static library into an already existing PE .exe, creating the desired effect. Just an idea; I never tried it, YMMV, but I think it might be worth a shot. – datenwolf Mar 13 '13 at 01:43
  • Your answer is still quite clearly wrong. It is factually incorrect. It's also trivial to export a global. As shown by the link found in the comments. – David Heffernan Mar 13 '13 at 07:13
  • @DavidHeffernan: How is it factually incorrect? It's perfectly possible to manipulate binaries on the lowest level, on par with an assembler. – datenwolf Mar 13 '13 at 11:42
  • It is factually incorrect because it is not tractable to force a static .lib into a Delphi module. Even if it was, it would be pointless to attempt to do so. – David Heffernan Mar 13 '13 at 11:46
  • @DavidHeffernan: I'd not push it into the Delphi Module, but into the final executable binary. All that the NVidia driver looks for is if the executable's PE does export this symbol with the magic value. If you prepare a static library that creates auch a symbol export and ibject it into the .exe PE the NVidia driver will see it. – datenwolf Mar 13 '13 at 11:51
  • The Delphi module **IS** the final executable binary. That's what a module is in Windows. Anyway, how exactly do you do this injecting process, and why is it easier than using `exports` in the Delphi source code? – David Heffernan Mar 13 '13 at 12:05
  • @DavidHeffernan: Of course using `exports` is the easy solution. But how I'd do it the other way? Using the GNU binutils I'd first use objcopy and objdump to split up the PE file into COFF files for the individual sections. Then I'd have my static library, or COFF file with the symbol to export prepared and re-assemble, err, re-link the whole thing into a PE, using the info obtained with objdump to put things into the right places. **Or**, I'd write myself a small tool, that allows me to modify a PE binary's symbol and constant data section, adding new symbols with predefined values. – datenwolf Mar 13 '13 at 12:13
  • That's just not practical. – David Heffernan Mar 13 '13 at 12:21
  • @DavidHeffernan: Depends. Symbol injection is a common problem, but I admit the tools are not very polished. But all it takes is one person to wrap the steps up and make an easily tangible tool for symbol injection and it's much more practical than an export statement. – datenwolf Mar 13 '13 at 12:57
  • @datenwolf - doable, sure, but practical? – Leonardo Herrera Mar 13 '13 at 14:40