Browse Source

dist: Add `prefer_discrete_gpu` option to force use of dedicated GPU

Currently only implemented on Windows.

Fixes #680
rdb 3 years ago
parent
commit
ffbfdb22e0
3 changed files with 46 additions and 3 deletions
  1. 9 3
      direct/src/dist/commands.py
  2. 30 0
      direct/src/dist/pefile.py
  3. 7 0
      pandatool/src/deploy-stub/deploy-stub.c

+ 9 - 3
direct/src/dist/commands.py

@@ -250,6 +250,7 @@ class build_apps(setuptools.Command):
         self.log_filename = None
         self.log_filename_strftime = False
         self.log_append = False
+        self.prefer_discrete_gpu = False
         self.requirements_path = os.path.join(os.getcwd(), 'requirements.txt')
         self.use_optimized_wheels = True
         self.optimized_wheel_index = ''
@@ -516,11 +517,16 @@ class build_apps(setuptools.Command):
             self.icon_objects.get('*', None),
         )
 
-        if icon is not None:
+        if icon is not None or self.prefer_discrete_gpu:
             pef = pefile.PEFile()
             pef.open(runtime, 'r+')
-            pef.add_icon(icon)
-            pef.add_resource_section()
+            if icon is not None:
+                pef.add_icon(icon)
+                pef.add_resource_section()
+            if self.prefer_discrete_gpu:
+                if not pef.rename_export("SymbolPlaceholder___________________", "AmdPowerXpressRequestHighPerformance") or \
+                   not pef.rename_export("SymbolPlaceholder__", "NvOptimusEnablement"):
+                    self.warn("Failed to apply prefer_discrete_gpu, newer target Panda3D version may be required")
             pef.write_changes()
             pef.close()
 

+ 30 - 0
direct/src/dist/pefile.py

@@ -605,6 +605,36 @@ class PEFile(object):
         if self.res_rva.addr and self.res_rva.size:
             self.resources.unpack_from(self.vmem, self.res_rva.addr)
 
+    def _mark_address_modified(self, rva):
+        for section in self.sections:
+            if rva >= section.vaddr and rva - section.vaddr <= section.size:
+                section.modified = True
+
+    def rename_export(self, old_name, new_name):
+        """ Renames a symbol in the export table. """
+
+        assert len(new_name) <= len(old_name)
+
+        new_name = new_name.ljust(len(old_name) + 1, '\0').encode('ascii')
+
+        start = self.exp_rva.addr
+        expdir = expdirtab(*unpack('<IIHHIIIIIII', self.vmem[start:start+40]))
+        if expdir.nnames == 0 or expdir.ordinals == 0 or expdir.names == 0:
+            return False
+
+        nptr = expdir.names
+        for i in range(expdir.nnames):
+            name_rva, = unpack('<I', self.vmem[nptr:nptr+4])
+            if name_rva != 0:
+                name = _unpack_zstring(self.vmem, name_rva)
+                if name == old_name:
+                    self.vmem[name_rva:name_rva+len(new_name)] = new_name
+                    self._mark_address_modified(name_rva)
+                    return True
+            nptr += 4
+
+        return False
+
     def get_export_address(self, symbol_name):
         """ Finds the virtual address for a named export symbol. """
 

+ 7 - 0
pandatool/src/deploy-stub/deploy-stub.c

@@ -62,6 +62,13 @@ volatile struct {
   // end up putting it in the .bss section for zero-initialized data.
 } blobinfo = {(uint64_t)-1};
 
+
+#ifdef _WIN32
+// These placeholders can have their names changed by deploy-stub.
+__declspec(dllexport) DWORD SymbolPlaceholder___________________ = 0x00000001;
+__declspec(dllexport) DWORD SymbolPlaceholder__ = 0x00000001;
+#endif
+
 #ifdef MS_WINDOWS
 #  define WIN32_LEAN_AND_MEAN
 #  include <windows.h>