5
votes

I’m working on a prototype that integrates WPF, Direct3D9 (using Microsoft’s D3DImage WPF class), and CUDA (I need to be able to generate a texture for the D3DImage on the GPU).

The problem is, CUDA doesn’t update my texture. No error codes are returned, the texture just stays unchanged. Even if I read after my own write, I don't see any changes. How to update my D3D9 texture?

I'm not even running any CUDA kernels, for debug purposes I only using cuMemcpy2D API to write the CUDA memory by copying some fake data from the CPU.

Here’s the code, it’s C# but I’ve placed native APIs in the comments:

static void updateTexture( Texture tx )
{
    var size = tx.getSize();

    using( CudaDirectXInteropResource res = new CudaDirectXInteropResource( tx.NativePointer, CUGraphicsRegisterFlags.None, CudaContext.DirectXVersion.D3D9 ) )  // cuGraphicsD3D9RegisterResource
    {
        res.Map();  // = cuGraphicsMapResources
        using( CudaArray2D arr = res.GetMappedArray2D( 0, 0 ) ) // cuGraphicsSubResourceGetMappedArray, cuArrayGetDescriptor. The size is correct here, BTW
        {
            // Debug code below - don't run any kernels for now, just call cuMemcpy2D to write the GPU memory
            uint[] arrWhite = new uint[ size.Width * size.Height ];
            for( int i = 0; i < arrWhite.Length; i++ )
                arrWhite[ i ] = 0xFF0000FF;
            arr.CopyFromHostToThis( arrWhite ); // cuMemcpy2D

            uint[] test = new uint[ size.Width * size.Height ];
            arr.CopyFromThisToHost( test ); // The values here are correct
        }
        res.UnMap(); // cuGraphicsUnmapResources
    }
    tx.AddDirtyRectangle();

    // Map again and check what's in the resource
    using( CudaDirectXInteropResource res = new CudaDirectXInteropResource( tx.NativePointer, CUGraphicsRegisterFlags.None, CudaContext.DirectXVersion.D3D9 ) )
    {
        res.Map();
        using( CudaArray2D arr = res.GetMappedArray2D( 0, 0 ) )
        {
            uint[] test = new uint[ size.Width * size.Height ];
            arr.CopyFromThisToHost( test ); // All zeros :-(
            Debug.WriteLine( "First pixel: {0:X}", test[ 0 ] );
        }
        res.UnMap();
    }
}
1
Have you tried different CUGraphicsRegisterFlags like WriteDiscard or SurfaceLDST to explicitly tell cuda that you will write to the texture? And CudaDirectXInteropResource should only be created once in the lifetime of your DirectX texture (to register resources is expensive)kunzmi
@kunzmi thanks, the second part of your comment (where you said about what you think is merely a performance problem with my code) was actually helpful.Soonts

1 Answers

5
votes

As hinted by the commenter, I’ve tried creating a single instance of CudaDirectXInteropResource along with the D3D texture. It worked.

It’s counter-intuitive and undocumented, but it looks like cuGraphicsUnregisterResource destroys the newly written data. At least on my machine with GeForce GTX 960, Cuda 7.0 and Windows 8.1 x64.

So, the solution — call cuGraphicsD3D9RegisterResource once per texture, and use cuGraphicsMapResources / cuGraphicsUnmapResources API to allow CUDA to access the texture data.