The Remix SDK exposes an API that gives applications access to the renderer inside the Remix Runtime.
-
Direct3D 9 Translation Layer: This component intercepts the D3D9 API and uses information in the API calls to reconstruct the scene hierarchy, then passes that to Remix's path traced renderer to generate the final image. This means that even if an application was built using older graphics technology, it can still benefit from the advanced lighting and rendering features of the Remix renderer. The source code for this component is available at: https://github.com/nvidiagameworks/dxvk-remix
-
Remix Bridge: This optional component converts D3D9 calls from 32-bit to 64-bit, which is necessary for running 32-bit applications since the Remix renderer operates exclusively in a 64-bit environment. Native 64-bit applications do not require the Remix Bridge. Source code for this component is hosted at https://github.com/nvidiagameworks/bridge-remix
The Remix SDK is designed to give developers direct access to the advanced features of the Remix Renderer, bypassing the limitations of the older Direct3D 9 API. This SDK allows for more flexible control over materials, lighting, and other graphical elements that D3D9 cannot handle.
It consists of a plain C header file with a straightforward API, and an optional C++ wrapper that can help reduce boilerplate code for projects written in C++. The API implementation itself is part of d3d9.dll in dxvk-remix.
To compile and set up the Remix SDK locally, first ensure that Requirements from the main Build instructions for dxvk-remix are met. Building the Remix SDK is similar to building the dxvk-remix project:
meson setup --buildtype release _Comp64ReleaseSDK
cd _Comp64ReleaseSDK
meson compile copy_sdk
After a successful build, the necessary SDK files will be located in the public/ folder:
- public/bin/: This directory contains all the needed .dll files for the Remix Renderer and the usd/ folder.
- public/include/: This directory contains all the needed .h header files for the Remix SDK.
Note that the d3d9.dll binary built this way is identical to the regular builds of dxvk-remix, but the file layout generated by the copy_sdk step is not. However, downloading a pre-built d3d9.dll and headers from our Github repository can be an alternative starting point if you don’t want to build dxvk-remix locally.
Note: the API described below is under development and may be subject to changes.
As with other rendering engines, there are common steps of initialiazation, resource registration (meshes, materials, lights), and submitting the said resources to each frame to be rendered.
remixapi_example_c.c contains a minimal example in C to render a path traced triangle using the Remix API.
How to compile remixapi_example_c? [click to open]
- Copy Remix SDK contents to the
dxvk-remix/tests/rtx/apps/RemixAPI_C/
folder- So there would be
RemixAPI_C/bin/
andRemixAPI_C/include/
folders
- So there would be
- From the Windows Start menu, search for
x64 Native Tools Command Prompt for VS 2019
or other version, but must bex64
, launch it- This step is needed to be able to use
cl.exe
(Microsoft C/C++ compiler)
- This step is needed to be able to use
cd <your dxvk-remix folder>\tests\rtx\apps\RemixAPI_C
cl -Iinclude remixapi_example_c.c user32.lib
- This will compile
.exe
- This will compile
- Launch the
remixapi_example_c.exe
. A triangle should be rendered:
-
To load the Remix Renderer library, call the helper function
remixapi_lib_loadRemixDllAndInitialize
. It loads the Remix Renderer's dynamic library (.dll
), and returns aremixapi_Interface
struct that contains all the RemixAPI functions.Why dynamic linking? [click to open]
- Remix API is using explicit dynamic linking rather than implicit dynamic linking or static linking. With explicit dynamic linking, an API user can avoid dealing with build systems in a target application: it is assumed that a target appication may have a legacy build system that might be time-consuming to modify.
Versioning [click to open]
-
When a target application (e.g.
.exe
) is being compiled with the API header, the version numbersREMIXAPI_VERSION_*
are statically bound into the compiled target app binaries. That way, the target app is compatible only with specific versions of Remix Renderer binaries (d3d9.dll
). -
The Renderer binaries loosely follows the Semantic Versioning, with the main difference on the development
0.y.z
versions:0.a.b
and0.c.d
are not compatible ifa != c
. -
If a target app is not compatible with a given Remix Renderer binaries, initialization will return
REMIXAPI_ERROR_CODE_INCOMPATIBLE_VERSION
error code.
-
To start the Remix Renderer, call
remixapi_Interface::Startup
providing a filledremixapi_StartupInfo
struct.- Note: an extra care is needed for
.sType
member in all of the Remix API structs, as.sType
value is used internally to determine a type of a pointer.
- Note: an extra care is needed for
The main resource types in the Remix API are: mesh, material, light. Each needs to be registered to be used in the rendering of a frame.
Mesh:
- To register, call
remixapi_Interface::CreateMesh
- A mesh (
remixapi_MeshInfo
) consists of a set of surfaces (remixapi_MeshInfoSurfaceTriangles
)- Each surface is a set of triangles, defined by vertex/index buffer
- Each surface can reference a material (i.e. a mesh can consist of different materials)
- Note: at the time of writing, the structure of a Remix API vertex (
remixapi_HardcodedVertex
) is defined statically, without an option to define the element offsets and types (position, normal, etc). A subject to change.
Material:
- To register, call
remixapi_Interface::CreateMaterial
specifyingremixapi_MaterialInfo
, but.pNext
must be a pointer to one of:remixapi_MaterialInfoOpaqueEXT
-- for a generic materialremixapi_MaterialInfoTranslucentEXT
-- for a glass material
- For the default values, corresponding default constructors can be examined in the C++ wrapper remix.h
- Note: at the time of writing, the material API is still not refined to work with non-file image data, and overall structure just reflects the internal representation of materials, which might be not as simple to use. The primary subject to change.
Light:
- To register, call
remixapi_Interface::CreateLight
specifyingremixapi_LightInfo
, but.pNext
must be a pointer to one of:remixapi_LightInfoSphereEXT
-- sphere light; or spot light if a light shaping is configuredremixapi_LightInfoRectEXT
-- rectremixapi_LightInfoDiskEXT
-- diskremixapi_LightInfoCylinderEXT
-- cylinderremixapi_LightInfoDistantEXT
-- distant (sun)remixapi_LightInfoDomeEXT
- dome (sky)
.hash
should be a unique ID, it is used to identify the light source between the current and previous frame for a more stable denoising / light sampling- Since lights are usually changing a lot (they move, their intensity varies, etc), to update a light with the new parameters, recreate it by calling
remixapi_Interface::DestroyLight
+remixapi_Interface::CreateLight
but with the same.hash
value as the old one
Push a camera, mesh instances and lights to define a scene for the current frame.
-
Call
remixapi_Interface::SetupCamera
- Either specify view / projection matrices in
remixapi_CameraInfo
- Or specify parameters in
remixapi_CameraInfoParameterizedEXT
, and link the struct toremixapi_CameraInfo::pNext
, so Renderer would calculate matrices internally
- Either specify view / projection matrices in
-
Call
remixapi_Interface::DrawInstance
to push a mesh instance with a corresponding transform. There can be many instances that reference a singleremixapi_MeshHandle
(instancing). -
Call
remixapi_Interface::DrawLightInstance
to push a light to the scene. -
Call
remixapi_Interface::Present
to render a frame and present to the window
Note: to set rtx.conf
options at runtime, use remixapi_Interface::SetConfigVariable
Note: remixapi_example_c.c contains all the steps listed above, and should draw a triangle.
While the given example is D3D9-agnostic, the API can be used interchangeably with D3D9. The main constraint is that Remix API is 64-bit only, which means that the game also must be built for 64-bit.
So given an existing 64-bit D3D9 application, here are the steps to integrate Remix API:
-
Ensure that the app works with the original Remix Runtime
-
In the D3D9 app's source files, there will be
IDirect3D9::CreateDevice
call or similar, so after that:- Call
remixapi_lib_loadRemixDllAndInitialize(L"d3d9.dll")
to init the Remix API - Call
remixapi_Interface::dxvk_RegisterD3D9Device
, passing the D3D9 device- Make a static_cast to
IDirect3DDevice9Ex*
, if needed
- Make a static_cast to
- Call
After that, Remix API calls can be used.
For example:
g_remix.SetConfigVariable("rtx.fallbackLightMode", timer() ? "2" : "0");
to turn on/off the fallback light programmatically.
Remix API is designed to be extensible and backward compatible.
To add new struct types, add a type and corresponding entry to remixapi_StructType
enum. Then follow the instructions in src/dxvk/rtx_render/rtx_remix_specialization.inl
. Add handling code to the src/dxvk/rtx_render/rtx_remix_api.cpp
to tie the API with an internal implementation. If a change is not compatible with previous versions, increase REMIXAPI_VERSION_MAJOR
; or other macros, according to versioning.
If adding a function, append the entry to remixapi_Interface
, but specififcally at the end of that struct, to preserve the compatibility with previous versions.
Note: Remix API was originally designed for the USD Hydra Delegate in the Remix Toolkit renderer, so it has been tested mostly for that specific use case.