Name

    NV_DX_interop

Name Strings

    WGL_NV_DX_interop

Contributors

    Michael Gold, NVIDIA
    Nuno Subtil, NVIDIA

Contact

    Nuno Subtil, NVIDIA Corporation (nsubtil 'at' nvidia.com)

Status

    Complete. Shipping with NVIDIA release 265 drivers, November 2010.

Version

    Last Modified Date:         10/11/2010
    Revision:                   1

Number

    407

Dependencies

    OpenGL 2.1 is required.

Overview

    This extension allows OpenGL to directly access DirectX buffers
    and surfaces.  A DirectX vertex buffer may be shared as an OpenGL
    buffer object and a DirectX surface may be shared as an OpenGL
    texture or renderbuffer object.

New Procedures and Functions

    BOOL wglDXSetResourceShareHandleNV(void *dxObject, HANDLE shareHandle);

    HANDLE wglDXOpenDeviceNV(void *dxDevice);
    BOOL wglDXCloseDeviceNV(HANDLE hDevice);
    HANDLE wglDXRegisterObjectNV(HANDLE hDevice, void *dxObject,
                                  GLuint name, GLenum type, GLenum access);
    BOOL wglDXUnregisterObjectNV(HANDLE hDevice, HANDLE hObject);
    BOOL wglDXObjectAccessNV(HANDLE hObject, GLenum access);
    BOOL wglDXLockObjectsNV(HANDLE hDevice, GLint count, HANDLE *hObjects);
    BOOL wglDXUnlockObjectsNV(HANDLE hDevice, GLint count, HANDLE *hObjects);

New Tokens

    Accepted by the <access> parameters of wglDXRegisterObjectNV and
    wglDXObjectAccessNV:

      WGL_ACCESS_READ_ONLY_NV             0x0000
      WGL_ACCESS_READ_WRITE_NV            0x0001
      WGL_ACCESS_WRITE_DISCARD_NV         0x0002

Additions to the WGL Specification

    OpenGL may directly access textures, surfaces and buffers created
    by DirectX.  A DirectX device is prepared for interoperability
    by calling

        HANDLE wglDXOpenDeviceNV(void *dxDevice);

    <dxDevice> is a pointer to a supported Direct3D device
    object. Supported devices are listed in the wgl.devicetypes table,
    along with applicable restrictions for each device. The return
    value is a handle to a GL/DirectX interop device.

    When wglDXOpenDeviceNV fails to open a Direct3D device, NULL is
    returned. To get extended error information, call GetLastError.
    Possible errors are as follows:

      ERROR_OPEN_FAILED        Could not open the Direct3D device.

      ERROR_NOT_SUPPORTED      The <dxDevice> is not supported.
                               This can be caused either by passing in
                               a device from an unsupported DirectX
                               version, or by passing in a device
                               referencing a display adapter that is
                               not accessible to the GL.

    Calling this entrypoint with an invalid <dxDevice> pointer results
    in undefined behavior and may result in data corruption or program
    termination.

    Versions of the operating system that support the Windows Display
    Driver Model (WDDM) support a sharing mechanism for DirectX
    resources that makes use of WDDM share handles. The application may
    obtain a share handle from the operating system to share a surface
    among several Direct3D devices.

    This extension accommodates, but does not require use of WDDM share
    handles. An application should only obtain a WDDM share handle at
    resource creation time if it will share the resource with non-GL
    clients.

    As of today, all versions of Microsoft Windows starting with Windows
    Vista use the Windows Display Driver Model, enabling the usage of
    WDDM share handles.

    If the application wishes to share a DirectX version 9 resource
    under a WDDM operating system, it is required that the Direct3D
    device that owns the resource be a Direct3D9Ex device.

    -------------------------------------------------------------------------
    DirectX device type      Device Restrictions
    -------------------------------------------------------------------------
    IDirect3DDevice9         can not be used on WDDM operating systems;
                             D3DCREATE_MULTITHREADED behavior flag must be
                             set at device creation time

    IDirect3DDevice9Ex       D3DCREATE_MULTITHREADED behavior flag must be
                             set at device creation time
    -------------------------------------------------------------------------
    Table wgl.devicetypes - Valid device types for the <dxDevice> parameter of
    wglDXOpenDeviceNV and associated restrictions.
    -------------------------------------------------------------------------

    If the application wishes to share a DirectX resource with GL and
    non-GL clients, it should request a share handle for the
    resource. It must also call

        BOOL wglDXSetResourceShareHandleNV(void *dxResource, HANDLE shareHandle);

    to associate the share handle with the DirectX resource prior to
    registering it with the GL. <dxResource> is a pointer to the DirectX
    resource that will be shared, <shareHandle> contains the share
    handle that the OS generated for the resource.

    The return value for wglDXSetResourceShareHandleNV is FALSE if
    this function is called more than once for any resource; called
    with an invalid <shareHandle> parameter; or called for a resource
    that is already being shared with the GL; otherwise, the return
    value is TRUE. On a version of the OS that does not support WDDM,
    calling wglDXSetResourceShareHandleNV returns TRUE but has no
    effect.

    Results are undefined if the <dxResource> pointer is invalid and
    may result in data corruption or program termination.

    Calling

        HANDLE wglDXRegisterObjectNV(HANDLE hDevice, void *dxResource,
                                     GLuint name, GLenum type, GLenum access);

    prepares a DirectX object for use by the GL.  <hDevice> is a
    GL/DirectX interop device handle, as returned by wglDXOpenDeviceNV.

    <dxResource> is a pointer to a DirectX resource to be registered
    with the GL. The resource must be of one of the types identified in
    table wgl.objtypes and must also obey the restrictions specified for
    that resource in table wgl.restrictions.

    <type> identifies the GL object type that will map to the DirectX
    resource being shared and must be one of the types enumerated in
    table wgl.objtypes.  <name> is the GL object name to be assigned
    to the DirectX resource in the namespace of the objects identified
    by <type> in the current GL context. The valid combinations of
    <type> and <dxResource> are described in table wgl.objtypes.

    <access> indicates the intended usage of the resource in GL and must
    be one of the following:

        WGL_ACCESS_READ_ONLY_NV indicates that GL will read the
        DirectX resource but will not modify it.  If GL attempts to
        modify the data store of the resource, the result is undefined
        and may include program termination.

        WGL_ACCESS_READ_WRITE_NV indicates that GL may read or write
        the data store of the resource.

        WGL_ACCESS_WRITE_DISCARD_NV indicates that any previous
        contents of the object may be discarded and GL may write to
        the resource.  Any data written by GL may be reliably read in
        subsequent operations.  The result of subsequently reading
        data outside the region written by GL is undefined.

    If the call is successful, the return value is a handle to a
    GL/DirectX interop object. A return value of NULL indicates that
    an error occurred. To obtain extended error information, call
    GetLastError. Possible errors are as follows:

      ERROR_INVALID_HANDLE    No GL context is made current to the
                              calling thread.

      ERROR_INVALID_DATA      Incorrect <name> <type> or <access>
                              parameters.

      ERROR_OPEN_FAILED       Opening the Direct3D resource failed.

    Calling wglDXRegisterObjectNV with an invalid <hDevice> handle
    results in undefined behavior and may result in data corruption or
    program termination.

    If the application explicitly requests a share handle for a
    DirectX resource, results are undefined (and may result in data
    corruption, incorrect DirectX operation or program termination) if
    wglDXRegisterObjectNV is called before calling
    wglDXSetResourceShareHandleNV for the same resource. This
    restriction does not apply to non-WDDM operating systems.

    --------------------------------------------------------------------------
    <type>              type of <name>     Valid DirectX resource types
    --------------------------------------------------------------------------
    TEXTURE_2D          texture            IDirect3DSurface9
                                           IDirect3DTexture9

    TEXTURE_3D          texture            IDirect3DVolumeTexture9

    TEXTURE_CUBE_MAP    texture            IDirect3DCubeTexture9

    TEXTURE_RECTANGLE   texture            IDirect3DSurface9
                                           IDirect3DTexture9

    RENDERBUFFER        renderbuffer       IDirect3DSurface9

    NONE                buffer             IDirect3DIndexBuffer9
                                           IDirect3DVertexBuffer9
    --------------------------------------------------------------------------
    Table wgl.objtypes - Valid values for the <type> parameter of
    wglDXRegisterObjectNV and associated object types for GL and
    DirectX.
    --------------------------------------------------------------------------

    --------------------------------------------------------------------------
    Resource Type            Resource Restrictions
    --------------------------------------------------------------------------
    IDirect3DSurface9        Must not be lockable

    IDirect3DTexture9        Memory pool must be D3DPOOL_DEFAULT

    IDirect3DCubeTexture9    Memory pool must be D3DPOOL_DEFAULT

    IDirect3DVolumeTexture9  Memory pool must be D3DPOOL_DEFAULT

    IDirect3DVertexBuffer9   Memory pool must be D3DPOOL_DEFAULT

    IDirect3DIndexBuffer9    Memory pool must be D3DPOOL_DEFAULT

   --------------------------------------------------------------------------
    Table wgl.restrictions - Restrictions on DirectX resources that can
    be registered via wglDXRegisterObjectNV
    --------------------------------------------------------------------------

    Before a GL object which is associated with a DirectX resource may
    be used, it must be locked.  The function

        BOOL wglDXLockObjectsNV(HANDLE hDevice, GLint count,
                                HANDLE *hObjects);

    attempts to lock an array of <count> interop objects.  <hObjects>
    is an array of length <count> containing the handles of the
    objects to be locked.

    A return value of TRUE indicates that all objects were
    successfully locked.  A return value of FALSE indicates an
    error. To get extended error information, call
    GetLastError. Possible errors are as follows:

      ERROR_BUSY            One or more of the objects in <hObjects>
                            was already locked.

      ERROR_INVALID_DATA    One or more of the objects in <hObjects>
                            does not belong to the interop device
                            specified by <hDevice>.

      ERROR_LOCK_FAILED     One or more of the objects in <hObjects>
                            failed to lock.

    If the function returns FALSE, none of the objects will be locked.

    Attempting to access an interop object via GL when the object is
    not locked, or attempting to access the DirectX resource through
    the DirectX API when it is locked by GL, will result in undefined
    behavior and may result in data corruption or program
    termination. Likewise, passing invalid interop device or object
    handles to this function has undefined results, including program
    termination.

    Locked objects are available for operations which read or write
    the data store, according to the access mode specified in
    wglDXRegisterObjectNV.  If a different access mode is required
    after the object has been registered, the access mode may be
    modified by calling

        BOOL wglDXObjectAccessNV(HANDLE hObject, GLenum access);

    <hObject> is an interop object handle returned by
    wglDXRegisterObjectNV and identifies the interop object for which
    the access mode should be modified.

    <access> is a new access mode with the same meaning as the
    <access> parameter of wglDXRegisterObjectNV.  The access mode may
    be modified only when an object is not locked and will affect
    subsequent lock operations.

    The return value is TRUE if the function succeeds. If an error
    occurs, the return will be FALSE. To get extended error
    information, call GetLastError. Possible errors are as follows:

      ERROR_INVALID_DATA      Invalid <access> parameter.

      ERROR_BUSY              <hObject> is currently locked for
                              GL access.

    Operations which attempt to read or write an object in a manner
    inconsistent with the specified access mode will result in
    undefined behavior and may result in data corruption or program
    termination.

    Calling wglDXObjectAccessNV with an invalid <hObject> parameter
    results in undefined behavior and may result in data corruption or
    program termination.

    In order to return control of an object to DirectX, it must be unlocked
    by calling

        BOOL wglDXUnlockObjectsNV(HANDLE hDevice, GLint count,
                                  HANDLE *hObjects);

    A return value of TRUE indicates that the objects were
    successfully unlocked and DirectX may now safely access them.  A
    return value of FALSE indicates that an error occurred. To get
    extended error information, call GetLastError. Possible errors are
    as follows:

      ERROR_NOT_LOCKED      One or more of the objects in <hObjects>
                            was not locked.

      ERROR_INVALID_DATA    One or more of the objects in <hObjects>
                            does not belong to the interop device
                            identified by <hDevice>.

      ERROR_LOCK_FAILED     One or more of the objects in <hObjects>
                            failed to unlock.

    If the function returns FALSE, none of the objects are unlocked.

    Results are undefined if any of the handles in <hObjects> are
    invalid and may result in data corruption or program termination.

    When access to a DirectX resource from GL is no longer required, the
    association between the GL object and the DirectX resource should be
    terminated by calling

        BOOL wglDXUnregisterObjectNV(HANDLE hObject);

    where <hObject> is the interop object handle returned by
    wglDXRegisterObjectNV.  Any subsequent attempt to access
    <hObject> will result in undefined behavior and may result in data
    corruption or program termination.

    A return value of TRUE indicates that the object was successfully
    unregistered and <hObject> is now invalid. A return value of FALSE
    indicates that an error occurred. To get extended error
    information, call GetLastError. Possible errors are as follows:

      ERROR_BUSY      <hObject> is currently locked for access
                      by the GL

    Results are undefined if <hObject> is invalid and may result in
    program termination or data corruption.

    When all interop operations have been completed, the connection
    between OpenGL and DirectX may be terminated by calling

        BOOL wglDXCloseDeviceNV(HANDLE hDevice);

    where <hDevice> is the interop device handle returned by
    wglDXOpenDeviceNV.  Once the device is closed, any attempt to
    access DirectX resources through associated GL handles will result
    in undefined behavior and may result in data corruption or program
    termination.

    A return value of TRUE indicates that the device was successfully
    closed and <hDevice> is now invalid. A return value of FALSE
    indicates an error. To get extended error information, call
    GetLastError. Possible errors are as follows:

        ERROR_INVALID_DATA          The Direct3D device failed to
                                    close.

    Calling this function with an invalid <hDevice> parameter results
    in undefined behavior and may result in data corruption or program
    termination.

Issues

    1) Should we support explicit usage of share handles under WDDM or
    disallow it entirely?

    RESOLUTION: We should support it. Implicit share handles are
    useful when writing code that's meant to be portable between WDDM
    and non-WDDM operating systems; explicit share handles are useful
    when writing an application that needs to share resources with
    non-GL clients.

    2) Can DirectX and OpenGL render concurrently to the same DirectX
    resource?

    RESOLUTION: Concurrent rendering by OpenGL and DirectX to the same
    resource is not supported.

    DISCUSSION: The Lock/Unlock calls serve as synchronization points
    between OpenGL and DirectX. They ensure that any rendering
    operations that affect the resource on one driver are complete
    before the other driver takes ownership of it.

    When sharing a large resource, applications can potentially desire
    concurrent access to different regions of the resource (e.g., if
    the application is drawing a user interface in DirectX with an
    OpenGL viewport occupying a region of it, where the UI and OpenGL
    regions do not overlap). In this case, more fine-grained
    synchronization could be achieved by not doing implicit
    synchronization on the driver side and providing primitives to the
    application to enable it to synchronize on it's own, for instance,
    by allowing a DirectX 9 event query to be mapped and used as a GL
    sync object. This is, however, beyond the scope of the current
    extension.

    3) If two GL contexts are sharing textures, what is the correct
    way to access a DirectX resource from both contexts?

    RESOLUTION: Sharing a DirectX resource among multiple GL contexts is
    best achieved without having shared namespaces among the GL
    contexts, by simply registering the texture on each GL context
    separately.

    If two GL contexts share namespaces, it is still necessary to lock
    the DirectX resource for each GL context that needs to access
    it. Note that only one GL context may hold the lock on the
    resource at any given time --- concurrent access from multiple GL
    contexts is not currently supported.

    4) How do driver control panel settings regarding anti-aliasing
    modes affect this extension?

    DISCUSSION: User-configurable system settings may allow users to
    force anti-aliasing for applications that do not support
    it. Usually, this causes the implementation to create multisampled
    surfaces for render targets that the application creates as
    non-multisampled.

    GL API semantics for textures can differ between multisample and
    non-multisample textures. If the application creates a DirectX
    render target that is to be bound as a GL texture, it will have no
    way to know that the surface is actually multisampled, but GL will
    require that it is bound to the TEXTURE_2D_MULTISAMPLE target
    instead of the TEXTURE_2D target. Because of this, it is
    recommended that render targets be bound to GL renderbuffers
    instead.

    Additionally, DirectX implementations are free to create render
    targets that do not match the number of samples that the app
    requested. Implementations are also free to create color and depth
    render targets with incompatible multisample modes. This can
    result in FBO completeness errors if incompatible color and depth
    render targets are bound for rendering to the same FBO. This
    problem also exists with pure DirectX applications and is not
    specific to this extension.

Sample Code

    Render to Direct3D 9 multisample color and depth buffers with
    OpenGL under WDDM:

    // create the Direct3D9Ex device:
    IDirect3D9Ex *direct3D;
    IDirect3DDevice9Ex *device;
    D3DPRESENT_PARAMETERS d3dpp;

    direct3D = Direct3DCreate9Ex(D3D_SDK_VERSION, &direct3D);

    <set appropriate device parameters in d3dpp>

    direct3D->CreateDevice(D3DADAPTER_DEFAULT,
                           D3DDEVTYPE_HAL,
                           hWnd,
                           D3DCREATE_HARDWARE_VERTEXPROCESSING |
                           D3DCREATE_PUREDEVICE |
                           D3DCREATE_MULTITHREADED,
                           &d3dpp,
                           &device);

    // create the Direct3D render targets
    IDirect3DSurface9 *dxColorBuffer;
    IDirect3DSurface9 *dxDepthBuffer;

    device->CreateRenderTarget(width, height,
                               D3DFMT_A8R8G8B8,
                               D3DMULTISAMPLE_4_SAMPLES, 0,
                               FALSE,
                               &dxColorBuffer,
                               NULL);

    device->CreateDepthStencilSurface(width, height,
                                      D3DFMT_D24S8,
                                      D3DMULTISAMPLE_4_SAMPLES, 0,
                                      FALSE,
                                      &dxDepthBuffer,
                                      NULL);

    // register the Direct3D device with GL
    HANDLE gl_handleD3D;
    gl_handleD3D = wglDXOpenDeviceNV(device);

    // register the Direct3D color and depth/stencil buffers as
    // 2D multisample textures in opengl
    GLuint gl_names[2];
    HANDLE gl_handles[2];

    glGenTextures(2, gl_names);

    gl_handles[0] = wglDXRegisterObjectNV(gl_handleD3D, dxColorBuffer,
                                          gl_names[0],
                                          GL_TEXTURE_2D_MULTISAMPLE,
                                          WGL_ACCESS_READ_WRITE_NV);

    gl_handles[1] = wglDXRegisterObjectNV(gl_handleD3D, dxDepthBuffer,
                                          gl_names[1],
                                          GL_TEXTURE_2D_MULTISAMPLE,
                                          WGL_ACCESS_READ_WRITE_NV);

    // attach the Direct3D buffers to an FBO
    glBindFramebuffer(GL_FRAMEBUFFER, fbo);
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
                           GL_TEXTURE_2D_MULTISAMPLE, gl_names[0]);
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
                           GL_TEXTURE_2D_MULTISAMPLE, gl_names[1]);
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
                           GL_TEXTURE_2D_MULTISAMPLE, gl_names[1]);

    // rendering loop
    while (!done) {
          <direct3d renders to the render targets>

          // lock the render targets for GL access
          wglDXLockObjectsNV(handleD3D, 2, gl_handles);

          <opengl renders to the render targets>

          // unlock the render targets
          wglDXUnlockObjectsNV(handleD3D, 2, gl_handles);

          <direct3d renders to the render targets and presents
           the results on the screen>
    }

Revision History

    Revision 1, 2010/11/10
     - Initial public revision
