To create your own Action
and benefit from CUDA and interoperability, follow these steps:
- Include
PluginInteropUnityCUDA
in your library. - Create a class (in this example,
MyAction
) that derives fromAction
inAction.h
:
#include "action.h"
class MyAction : public Action {
- Create a constructor that takes the necessary parameters (e.g., a pointer to a Unity texture and the texture's resolution):
#include "unityPlugin.h"
#include "texture.h"
MyAction(void* textureUnityPtr, int resolutionTexture) : Action()
{
_resolutionTexture = resolutionTexture;
// Create a Texture object that can be registered/mapped to CUDA
_texture = CreateTextureInterop(textureUnityPtr, resolutionTexture, resolutionTexture);
}
- Define a function to be called from Unity to get a pointer to
MyAction
and register it inPluginInteropUnityCUDA
:
// for mangling
extern "C" {
// Enables Unity C# to create and interact with MyAction
UNITY_INTERFACE_EXPORT MyAction* UNITY_INTERFACE_API
createMyAction(void* textureUnityPtr, int resolutionTexture)
{
return (new MyAction(textureUnityPtr, resolutionTexture));
}
}
- Override the functions
Start()
,Update()
, andOnDestroy()
as needed. In this example, we register and map the texture in CUDA and call a simple kernel:
int Start() override
{
// Perform one-time setup at start
_texture->registerTextureInCUDA();
_texture->mapTextureToSurfaceObject();
return 0;
}
int Update() override
{
// Call your kernel here
// Use the `surf2Dwrite` function to write into the texture
// (see https://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html?highlight=surf2dwrite#surf2dwrite)
// Use getSurfaceObjectArray() to get the cudaSurfaceObject_t
return 0;
}
int OnDestroy() override
{
// Unmap and unregister the texture
_texture->unmapTextureToSurfaceObject();
_texture->unRegisterTextureInCUDA();
return 0;
}
#include "action.h"
class MyAction : public Action {
public:
// Constructor with initialization arguments, such as a Unity texture pointer
MyAction(void* textureUnityPtr, int resolutionTexture) : Action()
{
_resolutionTexture = resolutionTexture;
// Create a Texture object that can be registered/mapped to CUDA
_texture = CreateTextureInterop(textureUnityPtr, resolutionTexture, resolutionTexture);
}
int Start() override
{
_texture->registerTextureInCUDA();
_texture->mapTextureToSurfaceObject();
return 0;
}
int Update() override
{
// Example kernel call (see SampleBasic project and sample_kernels.cu)
kernelCallerWriteTexture(
_texture->getDimGrid(),
_texture->getDimBlock(),
_texture->getSurfaceObject(),
GetTime(),
_texture->getWidth(),
_texture->getHeight()
);
return 0;
}
int OnDestroy() override
{
_texture->unmapTextureToSurfaceObject();
_texture->unRegisterTextureInCUDA();
return 0;
}
private:
Texture* _texture;
int _resolutionTexture;
};
extern "C" {
UNITY_INTERFACE_EXPORT MyAction* UNITY_INTERFACE_API
createMyAction(void* textureUnityPtr, int resolutionTexture)
{
return (new MyAction(textureUnityPtr, resolutionTexture));
}
}
To integrate your action in Unity and register it with the PluginInteropUnityCUDA
, follow these steps:
-
Create a C# class (e.g.,
MyActionUnity
) derived fromActionUnity
inActionUnity.cs
. This class represents your nativeMyAction
object in Unity. -
Import the function created in step 4 (e.g.,
createMyAction
) into your Unity C# code. -
Set the
_actionPtr
member to the return value of the imported function (e.g.,MyAction*
):
public class MyActionUnity : ActionUnity
{
const string _myDllName = "MyDllName"; // Specify your DLL name
[DllImport(_myDllName)]
private static extern IntPtr createMyAction(IntPtr textureUnityPtr, int resolutionTexture);
// Constructor to create the MyAction object
public MyActionUnity(RenderTexture rt) : base()
{
// Set the pointer to the native MyAction object
_actionPtr = createMyAction(rt.GetNativeTexturePtr(), rt.width);
}
}
-
Create another C# class (e.g.,
MyInteropHandler
) derived fromInteropHandler
inInteropHandler.cs
. This class will handle the Unity-side initialization and registration of your action. -
Override the
InitializeActions()
function to construct your action, register it withPluginInteropUnityCUDA
, and call itsStart()
function:
protected override void InitializeActions()
{
// Create a RenderTexture
RenderTexture _renderTexture = new RenderTexture(...);
// Construct the action
MyActionUnity myAction = new MyActionUnity(_renderTexture);
// Register the action with PluginInteropUnityCUDA
RegisterActionUnity(myAction, "myRegistrationKey");
// Call the overridden Start function
CallActionStart("myRegistrationKey");
}
- Override the
CallUpdateActions()
function to call the overriddenUpdate()
function:
protected override void CallUpdateActions()
{
// Call the overridden Update function
CallActionUpdate("myRegistrationKey");
}
- Override the
CallOnDestroy()
function to call the overriddenOnDestroy()
function:
protected override void CallOnDestroy()
{
// Call the overridden OnDestroy function
CallActionOnDestroy("myRegistrationKey");
}