Skip to content

Latest commit

 

History

History
191 lines (115 loc) · 10.5 KB

RemixSDK.md

File metadata and controls

191 lines (115 loc) · 10.5 KB

Remix SDK

The Remix SDK exposes an API that gives applications access to the renderer inside the Remix Runtime.

Remix Runtime components:

  • 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

Remix SDK Design

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.

Setting up the Remix SDK for development

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:

  1. meson setup --buildtype release _Comp64ReleaseSDK
  2. cd _Comp64ReleaseSDK
  3. 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.


Using the Remix SDK in your application

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]
  1. Copy Remix SDK contents to the dxvk-remix/tests/rtx/apps/RemixAPI_C/ folder
    • So there would be RemixAPI_C/bin/ and RemixAPI_C/include/ folders
  2. From the Windows Start menu, search for x64 Native Tools Command Prompt for VS 2019 or other version, but must be x64, launch it
    • This step is needed to be able to use cl.exe (Microsoft C/C++ compiler)
  3. cd <your dxvk-remix folder>\tests\rtx\apps\RemixAPI_C
  4. cl -Iinclude remixapi_example_c.c user32.lib
    • This will compile .exe
  5. Launch the remixapi_example_c.exe. A triangle should be rendered:

image info


Init

  1. To load the Remix Renderer library, call the helper function remixapi_lib_loadRemixDllAndInitialize. It loads the Remix Renderer's dynamic library (.dll), and returns a remixapi_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 numbers REMIXAPI_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 and 0.c.d are not compatible if a != c.

    • If a target app is not compatible with a given Remix Renderer binaries, initialization will return REMIXAPI_ERROR_CODE_INCOMPATIBLE_VERSION error code.


  2. To start the Remix Renderer, call remixapi_Interface::Startup providing a filled remixapi_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.

Resources

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 specifying remixapi_MaterialInfo, but .pNext must be a pointer to one of:
    • remixapi_MaterialInfoOpaqueEXT -- for a generic material
    • remixapi_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 specifying remixapi_LightInfo, but .pNext must be a pointer to one of:
    • remixapi_LightInfoSphereEXT -- sphere light; or spot light if a light shaping is configured
    • remixapi_LightInfoRectEXT -- rect
    • remixapi_LightInfoDiskEXT -- disk
    • remixapi_LightInfoCylinderEXT -- cylinder
    • remixapi_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

In Each Frame

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 to remixapi_CameraInfo::pNext, so Renderer would calculate matrices internally
  • Call remixapi_Interface::DrawInstance to push a mesh instance with a corresponding transform. There can be many instances that reference a single remixapi_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.


Remix API in the existing Direct3D 9 apps

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:

    1. Call remixapi_lib_loadRemixDllAndInitialize(L"d3d9.dll") to init the Remix API
    2. Call remixapi_Interface::dxvk_RegisterD3D9Device, passing the D3D9 device
      • Make a static_cast to IDirect3DDevice9Ex*, if needed

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.

Extensibility

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.