This directory contains the OpenAutomate SDK. It's intended for application developers who wish to instrument their applications so that NVIDIA can optimize the end-user experience for the application on NVIDIA hardware as efficiently as possible.
The OpenAutomate SDK has been designed to be as unobtrusive and easy to integrate as possible for developers. All code that will be added to the application is provided as source code.
For frequently asked questions, please see the Frequently Asked Questions (FAQ) document.
Instrumenting an application with the OpenAutomate SDK allows NVIDIA to:
All of the above features are necessary for NVIDIA to efficiently test the application within its testing labs. The ability to set options persistently is also necessary to deliver optimal application options to the end-user.
To be OpenAutomate compatible, an application must have the following:
-openautomate
' that takes a single opaque argument, to put the application into OpenAutomate mode.The instrumented application must add a command-line option -openautomate
that accepts an opaque string as an option. It must have the form:
app.exe -openautomate opaque_opt_str
If this command-line is detected, the application must enter OpenAutomate mode by first calling oaInit()
, passing it the option string.
Immediately after oaInit()
is called, the application must enter the OpenAutomate command loop, by calling oaGetNextCommand()
repeatedly until OA_CMD_EXIT
or OA_CMD_RUN
is returned. Here's an example:
while(1)
{
oaInitCommand(&Command);
switch(oaGetNextCommand(&Command))
{
/* No more commands, exit program */
case OA_CMD_EXIT:
return;
/* Run as normal */
case OA_CMD_RUN:
RunApp();
return;
/* Enumerate all in-game options */
case OA_CMD_GET_ALL_OPTIONS:
GetAllOptions();
break;
/* Return the option values currently set */
case OA_CMD_GET_CURRENT_OPTIONS:
GetCurrentOptions();
break;
/* Set all in-game options */
case OA_CMD_SET_OPTIONS:
SetOptions();
break;
/* Enumerate all known benchmarks */
case OA_CMD_GET_BENCHMARKS:
GetBenchmarks();
break;
/* Run a benchmark */
case OA_CMD_RUN_BENCHMARK:
RunBenchmark(Command.BenchmarkName);
break;
}
}
Each of the seven commands must be supported by the application.
The application should cleanup and exit as soon as possible.
This command instructs the application to run as normal; it should run as if OpenAutomate mode was never invoked. However, when the user chooses to exit the application, the application must not exit the process. Instead, it should cleanup and return back to the command loop, calling oaGetNextCommand().
The application must enumerate all options available to the end user. For each available option, oaAddOption() must be called. For options of type OA_TYPE_ENUM options oaAddOption() must be called for each possible enumerant value. See the Enumerating Options section within this document for more information.
The application should call oaAddOptionValue() for each available option, to enumerate what each option is currently set to.
The application should call oaGetNextOption() repeatedly, until it returns NULL. The application should persistently (between invocations of the application) set the option value to the value indicated by the oaNamedOption struct pointer returned:
while((Option = oaGetNextOption()) != NULL)
{
/*
* Set option value to persist for subsequent runs of the game
* to the given value. Option->Name will be the name of the value,
* and Option->Value will contain the appropriate value.
*/
}
The application should enumerate all known benchmarks. Benchmark is loosely defined as any available automated test.
The application should run the benchmark named by the BenchmarkName field returned in the struct by oaGetNextCommand(). There are three callback functions that should be called by the application:
void oaStartBenchmark(void)
— The application should call oaStartBenchmark() right before the benchmark starts. It should be called before any CPU or GPU computation is done for the first frame.void oaDisplayFrame(oaInt frame)
— This should be called right before the final present call is called for each frame.void oaEndBenchmark(void)
— This should be called after the last frame is rendered in the benchmark.In addition to the callbacks, oaAddResultValue() or oaAddFrameValue() may optionally be called in order to return benchmark scores, or any test results. oaAddResultValue() must be called after the last call to oaDisplayFrame() (on the last frame), and before oaEndBenchmark(). oaAddFrameValue() must be called each frame, right before oaDisplayFrame() is called.
The OpenAutomate SDK supports options of different data types:
OA_TYPE_STRING
— String valuesOA_TYPE_INT
— Integer valuesOA_TYPE_FLOAT
— Floating-point valuesOA_TYPE_ENUM
— Enumerant valuesOA_TYPE_BOOL
— Boolean valuesFor all data types except OA_TYPE_ENUM, oaAddOption() is called once per option.
oaAddOption() takes a pointer to a oaNamedOption struct as input. The struct must first be initialized with the oaInitOption() function.Every option must have the following fields initialized:
DataType
- The data type (e.g. OA_TYPE_INT) of the optionName
- A string containing the exact name of the parameter as seen by the end-user of the applicationFor options of type OA_TYPE_ENUM, oaAddOption() is called once per possible enumerant value of that option. The field Value.Enum must be set to each possible enumerant value.
For example, an option named Resolution with values 640x480, 1024x768, and 1600x1200 would be defined with the following code:
{
oaNamedOptionStruct Option;
oaInitOption(&Option);
Option.Name = "Resolution";
Option.DataType = OA_TYPE_ENUM;
Option.Value.Enum = "640x480";
oaAddOption(&Option);
Option.Value.Enum = "1024x768";
oaAddOption(&Option);
Option.Value.Enum = "1600x1200"; oaAddOption(&Option);
}
If possible, all enumerant values should be sorted such that the first enumerant value produces the lowest quality and the last enumerant value produces the highest quality. Quality is obviously subjective, but in the case of an option such as Resolution, the order is obvious.
Options with numeric data types OA_TYPE_INT and OA_TYPE_FLOAT are assumed to have open and continues ranges for possible values by default. Options can be limited to ranges optional steps by setting the NumSteps, MinValue, and MaxValue fields. NumSteps can be set to:
NumSteps = -1
— If the range is openNumSteps = 0
— If it's closed, but continuous within the rangeNumSteps > 0
— If the range is divided up into NumSteps number of pointsMinValue.Int and MaxValue.Int, or MinValue.Float and MaxValue.Float must be set to the appropriate range values for options of OA_TYPE_INT and OA_TYPE_FLOAT respectively.
For example, a floating point parameter named Quality ranging from 1.0 to 5.0 with increments of 0.25 (e.g. 1.0, 1.25, 1.5, 1.75, 2.0, ... 4.75, 5.0) can be defined with the following code:
{
oaNamedOptionStruct Option;
oaInitOption(&Option);
Option.Name = "Quality";
Option.DataType = OA_TYPE_FLOAT;
Option.NumSteps = 16;
Option.MinValue.Float = 1.0;
Option.MaxValue.Float = 5.0;
oaAddOption(&Option);
}
Options may be grouped into hierarchical namespaces by using the reserved separator / within the option name, similar to standard filesystem path naming conventions.
If hierarchical namespaces are not used, all available options are assumed to be visible to the end-user, if they were to run the application outside of OpenAutomate mode.
If hierarchical namespaces are used, care must be taken to delineate between options that are exposed directly to the end-user, and ones that are not. Options under the top-level namespace User/ are assumed to be directly visible to the end-user. All other options are assumed to not be directly visible.
The special character / can be used within the name of an option by escaping it with an additional //. For example, User/In//Out would represent the option named In/Out in the top-level namespace User.
Often, applications have options that are enabled only when some other parent option's value meets a certain condition. The OpenAutomate SDK supports such dependencies, if the condition can be expressed with the form:
ParentVal EXP Constant
Where ParentVal is the value of the parent option, Constant is some constant value of the same type as ParentVal, and EXP is one of:
OA_COMP_OP_EQUAL
— Equality (e.g. ==)OA_COMP_OP_NOT_EQUAL
— Inequality (e.g. !=)OA_COMP_OP_GREATER
— Greater than (e.g. >)OA_COMP_OP_LESS
— Less than (e.g. <)OA_COMP_OP_GREATER_OR_EQUAL
— Greater than or equal to (e.g. >=)OA_COMP_OP_LESS_OR_EQUAL
— Less than or equal to (e.g. <=)If a dependency exists, it can be setup by setting the subfields Dependency.ParentName, Dependency.ComparisonVal, and Dependency.ComparisonOp. For example, if an option named Volume is dependent on a boolean parent option named Sound Enabled equaling OA_ON for it to be enabled:
{
oaNamedOptionStruct Option;
oaInitOption(&Option);
Option.Name = "Volume";
Option.DataType = OA_TYPE_FLOAT;
Option.Dependency.ParentName = "Sound Enabled";
Option.Dependency.ComparisonOp = OA_COMP_OP_EQUAL;
Option.Dependency.ComparisonVal.Bool = OA_ON;
Option.MinValue.Float = 0;
Option.MaxValue.Float = 10;
Option.NumSteps = 0;
oaAddOption(&Option);
}
The application may send various signals at various points throughout its run via the oaSendSignal() function:
oaBool oaSendSignal(oaSignalType signal, void *param);
Some signals may require a parameter param. For those that don't, a NULL should be passed in. The available signals are:
OA_SIGNAL_SYSTEM_REBOOT
Some benchmarks and tests require a reboot mid-run. This signal requests a safe reboot. After the call to oaSendSignal() completes, the application must:
param must be passed in as NULL.
OA_SIGNAL_ERROR
This signal raises an error exception. param must point to a valid oaMessage. The Error field of the oaMessage object should be set to the appropriate oaErrorType value, and the Message field either be NULL or point to an error message. oaInitMessage must be called on the oaMessage object before settings these values.
This signal may be used for warnings (non-fatal errors), and log messages by setting the Error field of the oaMessage object to OA_ERROR_WARNING and OA_ERROR_LOG respectively.
The following convenience macros are provided for raising errors, warnings, and log messages:
OA_RAISE_ERROR(error_type, message_str)
OA_RAISE_WARNING(message_str)
OA_RAISE_LOG(message_str)
Building your application with the SDK is intentionally simple. It requires only three files from the SDK to be included in your project:
inc/OpenAutomate.h
inc/OpenAutomate_Internal.h
src/OpenAutomate.c
inc/OpenAutomate.h is the only include file your application needs to include.
See examples/simple_app/simple_app.cpp for an example dummy application instrumented with the OpenAutomate SDK. To build the application, along with a simple plug-in (simple_plugin.dll) to run with the simple application, simply load the included Visual Studio solution OpenAutomate.sln and build all. The resulting binaries will be in the debug sub-directory--release if you choose the release target--in the root of the SDK. Once built, you can run the simple application with the command-line:
.\exe\simple_app.exe -openautomate plugins\simple_plugin.dll
simple_plugin.dll will run simple_app through various commands, and write out the result to stderr. The output should look something like:
simple_app: Reading options file ".simple_app_options.txt".
IN AddOption: 'User/Resolution'
IN AddOption: 'User/Resolution'
IN AddOption: 'User/Resolution'
IN AddOption: 'User/AA'
IN AddOption: 'User/AA'
IN AddOption: 'User/AA'
IN AddOption: 'User/Sound'
IN AddOption: 'User/Music Enabled'
IN AddOption: 'User/Enemy Density'
IN AddOption: 'Compression Level'
IN AddOption: 'Texture Quality'
IN AddOption: 'Texture Size'
IN AddOption: 'Texture Size'
IN AddOption: 'Texture Size'
Current option (int)'Compression Level' = 10
Current option (float)'Texture Quality' = 19.402985
Current option (enum)'Texture Size' = 128
Current option (enum)'User/AA' = Off
Current option (int)'User/Enemy Density' = 83
Current option (bool)'User/Music Enabled' = 1
Current option (enum)'User/Resolution' = 1024x768
Current option (bool)'User/Sound' = 1
simple_app: Writing options file ".simple_app_options.txt".
IN AddBenchmark: forest
IN AddBenchmark: crates
IN AddBenchmark: map1
Benchmark started
Result value (int)'Score' = 18249
Result value (float)'Some other score' = 29.140000
Benchmark ended
Total time = 1s
Avg. FPS = 50.000000
Applications that have OpenAutomate integrated--and are thus "OpenAutomate Enabled"--must register themselves when they're installed on the system, so that applications interested in invoking OpenAutomate Enabled applications may easily find them on the system, without doing a filesystem scan.
Application registration is a simple matter of creating a file with name/value pairs, or creating some registry keys (Windows only).
Applications searching for installed OpenAutomate Enabled applications will search various roots, building a list of available applications. There is precedence in the search order, so that if the same application definition file or registry entry exists under more than one root, the location with higher priority overrides the other.
The locations searched from higher to lower precedence are:
Where:
For registration via the filesystem, a file (format detailed below) must be created with the given path (e.g. <HOME>/.openautomate/<DEV_NAME>/<APP_NAME>/<APP_BUILD_NAME>). The name/value pairs will be stored within this file.
For registration via the Windows registry, a key with the given path must be created, and the name/value pairs are stored as values under this key.
The following name/value pairs must be defined:
All of the OpenAutomate functions that receive or return strings are assumed to be UTF-8 encoded strings. This simplifies plug-in development, while still supporting all languages. Furthermore, it maintains compatibility with standard ASCII strings without any extra effort.
Utility functions to register and unregister the application are provided with the SDK. User's of OpenAutomate are free to use the functions directly, or as example. Please see OpenAutomateUtil.h and OpenAutomateUtil.c for more information.
Upon uninstallation of the application, any registration files or registry settings registering the application must be deleted.
Here's an example registration file:
OAREG 1.0
INSTALL_ROOT_PATH: c:\Program Files\My Company\My Game
ENTRY_EXE: c:\Program Files\My Company\My Game\Bin\mygame.exe -i -o
INSTALL_DATETIME: 2008-05-31 15:01:02
REGION: en_US|ko_KR
The OpenAutomate SDK can be integrated to a game application in a number of ways and it is up to the game developers to decide which way to use. Examples are:
#include SDKPATH/OpenAutomate.h
to all C/C++ files that use OpenAutomate calls.exe
against OpenAutomate library.This is the simplest and the preferable OpenAutomate integration method.There is no overhead of separate project, no project settings headache and game developer will never have any link problems related to OpenAutomate. The recommended integration sequence is following:
\ThirdParty\OpenAutomate
. Upgrading to the next OpenAutomate version will require a single directory replacement. There may be several OpenAutomate versions in the ThirdParty
directory, put the latest into a directory named something like 'OpenAutomate' (without the version name), and it will eliminate any project changes on OpenAutomate upgrades.OpenAutomate\OpenAutomate.h
header (OA is located in a directory such as ThirdParty/OpenAutomate
and ThirdParty is in the project include paths).OpenAutomate.c
to the application project (or some library project). It should be included only once.If there are warnings or compilations errors please report them to your DevTech support engineer, OpenAutomate-Support@nvidia.com.
NVIDIA® GameWorks™ Documentation Rev. 1.0.220830 ©2014-2022. NVIDIA Corporation and affiliates. All Rights Reserved.