|
| 1 | +"""Execute complete production Nukem setters and provider UI routes. |
| 2 | +
|
| 3 | +The real transition admission is used; the OS environment and DLL callback are |
| 4 | +stand-ins. This tests CPU call ordering, not the DLL's configuration internals. |
| 5 | +""" |
| 6 | +import argparse |
| 7 | +from pathlib import Path |
| 8 | +import subprocess |
| 9 | +import tempfile |
| 10 | +from test_shutdown_routing import function |
| 11 | + |
| 12 | +ROOT = Path(__file__).resolve().parents[1] |
| 13 | +PRELUDE = r''' |
| 14 | +#include "framegen/ProviderCallAdmission.h" |
| 15 | +#include <unordered_set> |
| 16 | +#include <functional> |
| 17 | +#include <future> |
| 18 | +#include <chrono> |
| 19 | +#include <string> |
| 20 | +#include <stdexcept> |
| 21 | +#include <iostream> |
| 22 | +#include <cstdlib> |
| 23 | +enum class FGNvngxReplacement { Nukems, Other }; |
| 24 | +int writes=0,refreshes=0,checks=0; |
| 25 | +bool environmentOK=true; |
| 26 | +std::wstring key,value; |
| 27 | +std::function<void()> callback; |
| 28 | +bool SetEnvironmentVariableW(const wchar_t* k,const wchar_t* v) { |
| 29 | + ++writes;key=k;value=v;return environmentOK; |
| 30 | +} |
| 31 | +void refresh(){++refreshes;if(callback)callback();} |
| 32 | +void check(bool ok){if(!ok){std::cerr<<"settings check "<<checks+1<<" failed\n";std::exit(2);}++checks;} |
| 33 | +struct Base { FGNvngxReplacement type=FGNvngxReplacement::Nukems; FGNvngxReplacement getType(){return type;} }; |
| 34 | +struct Nvngx_Nukems:Base { |
| 35 | + void (*_refreshGlobalConfiguration)()=refresh; |
| 36 | + bool is120orNewer() const {return _refreshGlobalConfiguration!=nullptr;} |
| 37 | + bool setSetting(const wchar_t*,const wchar_t*); |
| 38 | + bool setDebugView(bool);bool setInterpolatedOnly(bool); |
| 39 | +} provider; |
| 40 | +struct Nvngx_FG { |
| 41 | + inline static ProviderCallAdmission _calls; |
| 42 | + inline static std::unordered_set<void*> _dx12InitAttempts,_vulkanInitAttempts; |
| 43 | + struct Publication {bool ready;int peeks;Base* Peek(){++peeks;return ready?&provider:nullptr;}}; |
| 44 | + inline static Publication _provider{true,0}; |
| 45 | + static bool setDebugView(bool);static bool setInterpolatedOnly(bool); |
| 46 | +}; |
| 47 | +''' |
| 48 | +CHECKS = r''' |
| 49 | +int main(){ |
| 50 | + for(auto setter:{Nvngx_FG::setDebugView,Nvngx_FG::setInterpolatedOnly}) { |
| 51 | + int before=writes; |
| 52 | + check(!setter(true)&&writes==before); // No Init footprint: no lazy load or environment write. |
| 53 | + Nvngx_FG::_dx12InitAttempts.insert(&provider); |
| 54 | + int peeks=Nvngx_FG::_provider.peeks; |
| 55 | + {auto busy=Nvngx_FG::_calls.TryOperation();check(!setter(true)&&writes==before&&Nvngx_FG::_provider.peeks==peeks);} |
| 56 | + {auto busy=Nvngx_FG::_calls.TryTransition();check(!setter(true)&&writes==before&&Nvngx_FG::_provider.peeks==peeks);} |
| 57 | + Nvngx_FG::_provider.ready=false;check(!setter(true)&&writes==before);Nvngx_FG::_provider.ready=true; |
| 58 | + provider.type=FGNvngxReplacement::Other;check(!setter(true)&&writes==before);provider.type=FGNvngxReplacement::Nukems; |
| 59 | + provider._refreshGlobalConfiguration=nullptr;check(!setter(true)&&writes==before);provider._refreshGlobalConfiguration=refresh; |
| 60 | + environmentOK=false;int calls=refreshes; |
| 61 | + check(!setter(true)&&writes==before+1&&refreshes==calls);environmentOK=true; |
| 62 | + callback=[setter]{ |
| 63 | + auto work=std::async(std::launch::async,[setter]{ |
| 64 | + return !setter(false)&&!Nvngx_FG::_calls.TryOperation()&&!Nvngx_FG::_calls.TryTransition(); |
| 65 | + }); |
| 66 | + check(work.wait_for(std::chrono::seconds(2))==std::future_status::ready&&work.get()); |
| 67 | + }; |
| 68 | + check(setter(true)&&value==L"1"&&refreshes==calls+1); |
| 69 | + check(key==(setter==Nvngx_FG::setDebugView?L"DLSSGTOFSR3_EnableDebugOverlay":L"DLSSGTOFSR3_EnableInterpolatedFramesOnly")); |
| 70 | + callback={};check(setter(false)&&value.empty()&&refreshes==calls+2); |
| 71 | + check(bool(Nvngx_FG::_calls.TryOperation())&&bool(Nvngx_FG::_calls.TryOperation())); |
| 72 | + callback=[]{throw std::runtime_error("DLL callback");};bool threw=false; |
| 73 | + try{setter(true);}catch(const std::runtime_error&){threw=true;} |
| 74 | + check(threw&&bool(Nvngx_FG::_calls.TryTransition()));callback={}; |
| 75 | + Nvngx_FG::_dx12InitAttempts.clear();Nvngx_FG::_vulkanInitAttempts.insert(&provider); |
| 76 | + check(setter(true));Nvngx_FG::_vulkanInitAttempts.clear(); |
| 77 | + before=writes;check(!setter(false)&&writes==before); |
| 78 | + } |
| 79 | + std::cout<<"PASS: "<<checks<<" provider settings checks\n"; |
| 80 | +} |
| 81 | +''' |
| 82 | + |
| 83 | + |
| 84 | +def main(): |
| 85 | + parser = argparse.ArgumentParser() |
| 86 | + parser.add_argument('--compiler', required=True) |
| 87 | + parser.add_argument('--driver') |
| 88 | + args = parser.parse_args() |
| 89 | + proxy = (ROOT/'OptiScaler/framegen/nvngx/Nvngx_FG.cpp').read_text(encoding='utf-8') |
| 90 | + nukem = (ROOT/'OptiScaler/framegen/nvngx/Nvngx_Nukems.cpp').read_text(encoding='utf-8') |
| 91 | + cpp = PRELUDE |
| 92 | + for name in ('setDebugView', 'setInterpolatedOnly'): |
| 93 | + cpp += function(proxy, 'bool Nvngx_FG::'+name+'(') |
| 94 | + cpp += function(nukem, 'bool Nvngx_Nukems::'+name+'(') |
| 95 | + cpp += function(nukem, 'bool Nvngx_Nukems::setSetting(') + CHECKS |
| 96 | + with tempfile.TemporaryDirectory(prefix='aurora-provider-settings-') as directory: |
| 97 | + path = Path(directory) |
| 98 | + test, exe = path/'test.cpp', path/'test.exe' |
| 99 | + test.write_text(cpp, encoding='utf-8') |
| 100 | + command = [args.compiler] + ([args.driver] if args.driver else []) |
| 101 | + if Path(args.compiler).stem.lower() == 'cl': |
| 102 | + command += ['/nologo', '/EHsc', '/std:c++20', '/I'+str(ROOT/'OptiScaler'), str(test), '/Fe:'+str(exe)] |
| 103 | + else: |
| 104 | + command += ['-std=c++20', '-pthread', '-I'+str(ROOT/'OptiScaler'), str(test), '-o', str(exe)] |
| 105 | + subprocess.run(command, cwd=path, check=True) |
| 106 | + subprocess.run([str(exe)], cwd=path, check=True, timeout=25) |
| 107 | + |
| 108 | + |
| 109 | +if __name__ == '__main__': |
| 110 | + main() |
0 commit comments