Update DX11 texture asynchronously in native plugin?

Sorry for the long question :smiley:

tl;dr version :slight_smile: Is it possible to update DirectX 11 textures asynchronously in native plugin (C++)?

I’ve written a plugin that retrieves data from Kinect.
Currently, color stream data is written to a texture created by Unity in a separate thread in the plugin using DirectX 9 as shown in the example below.

D3DLOCKED_RECT lockedRectangle;
colorFrameTextureDX9->LockRect(0, &lockedRectangle, NULL, 0);
memcpy(lockedRectangle.pBits, colorFrameMat.data, colorFrameMat.total() * colorFrameMat.channels());
colorFrameTextureDX9->UnlockRect(0);

With DX9 this works beautifully. As far as I know calling LockRect on a DX9 texture locks the texture data and memcpy after that is thread safe.


Using this code sample from unity I’ve added support for DX11 textures.

ID3D11DeviceContext *ctx = NULL;
device->GetImmediateContext(&ctx); // Device is sent from Unity

D3D11_TEXTURE2D_DESC desc;
colorFrameTextureDX11->GetDesc(&desc);
ctx->UpdateSubresource(colorFrameTextureDX11, 0, NULL, colorFrameMat.data, colorFrameMat.cols * colorFrameMat.channels(), 0);
ctx->Release();

When Unity is run in DX11 mode, this runs perfectly for a few second after which it crashes without error report. I believe the problem is in using UpdateSubresource method which doesn’t lock the texture causing simultaneous access from Unity’s rendering pipeline and plugin thread.

In DX11 documentation I came across the Map/Unmap methods for updating textures which work similarly to LockRect/UnlockRect methods from DX9. However these methods can only be used with DX11 textures created as D3D11_USAGE_DYNAMIC and the texture from Unity is created as D3D11_USAGE_DEFAULT.

Is it possible to change or recreate the texture created in Unity with different usage flags?

Thanks in advance to anyone who even read it all :smiley:

@joshko I am currently working on a similar task and would like to know if you have found a solution?,@joshko I am currently working on a similar task and would like to know if you have found a solution?

@buFFalo94
@joshko
Hello.
In Unity in order to update the texture, it has to be done from the rendering thread. You do this by calling GL.IssuePluginEvent(_nativeCallback, rID) where nativecallback is a function that does the update, and rID is an integer that this function will receive. You cannot send anything else to this function.
So in order for this to work you will have to make at least three calls and maybe even four (if you want a return value).

  1. Get the nativeCallback from the plugin. It should be saved as System.IntPtr.
  2. Set all the variables for your thread function - store them in a struct and save it in map<int,renderStruct> where the int is the rID that you will be passing to your render thread, so he will be able to find all the parameters.
  3. Call GL.IssuePluginEvent(). From the function that will be called find your struct in the map by using the rID you provided in a call. Note that render thread functions always return void.
  4. If you have a return value it should be saved in a different map and retrieved using fourth function that will find the result using same rID.

And now I have a question for you - You said that you managed to create D3D11 texture from the native. Every time I try to do it, by using the same method described above, I get an error from Texture2D.CreateExternalTexture - it crashes with Access violation reading location 0x0000000000000003 in UnityPlayer.dll!TexturesD3D11Base::RegisterNativeTexture(struct ID3D11ShaderResourceView *)
Please explain to me how did you manage to initialize a texture from the native side.