Skip to content

Interop with other DirectX code

Austin Kinross edited this page Jul 8, 2017 · 1 revision

Overview

  • ANGLE supports interop with other DirectX code using shared D3D textures
  • Interop can work with code using Direct3D11, Direct2D, Win2D, video playback and more

Demo

ANGLE and Win2D interop

The above example shows Win2D's "Burning Text Example" being used inside an OpenGL ES scene, which is rendered using ANGLE. Both the flames on the text (rendered by Win2D) and the cube (rendered by ANGLE) update every frame.


Using other DirectX content in an OpenGL ES (ANGLE) scene

  1. In your DirectX code, make sure you have a D3D11 Texture2D with the D3D11_RESOURCE_MISC_SHARED flag. For example, you could create one on your own D3D11 device like this:
    D3D11_TEXTURE2D_DESC texDesc = { 0 };
    texDesc.Width = width;
    texDesc.Height = height;
    texDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
    texDesc.MipLevels = 1;
    texDesc.ArraySize = 1;
    texDesc.SampleDesc.Count = 1;
    texDesc.SampleDesc.Quality = 0;
    texDesc.Usage = D3D11_USAGE_DEFAULT;
    texDesc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;
    texDesc.CPUAccessFlags = 0;
    texDesc.MiscFlags = D3D11_RESOURCE_MISC_SHARED;

    ComPtr<ID3D11Texture2D> d3dTex;
    HRESULT hr = mDevice->CreateTexture2D(&texDesc, nullptr, &d3dTex);
    if FAILED(hr)
    {
        // error handling code
    }
  1. Get the shared HANDLE to this D3D texture, and pass it into ANGLE to create an EGL surface. For example:
    ComPtr<IDXGIResource> dxgiResource;
    HANDLE sharedHandle;
    hr = d3dTex.As(&dxgiResource);
    if FAILED(hr)
    {
        // error handling code
    }

    hr = dxgiResource->GetSharedHandle(&sharedHandle);
    if FAILED(hr)
    {
        // error handling code
    }

    EGLSurface surface = EGL_NO_SURFACE;

    EGLint pBufferAttributes[] =
    {
        EGL_WIDTH, width,
        EGL_HEIGHT, height,
        EGL_TEXTURE_TARGET, EGL_TEXTURE_2D,
        EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGBA,
        EGL_NONE
    };

    surface = eglCreatePbufferFromClientBuffer(mEglDisplay, EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE, sharedHandle, mEglConfig, pBufferAttributes);
    if (surface == EGL_NO_SURFACE)
    {
        // error handling code
    }
  1. Bind this EGL surface to a GL texture
    GLuint glTex;

    glGenTextures(1, &glTex);
    glBindTexture(GL_TEXTURE_2D, glTex);

    eglBindTexImage(mEglDisplay, surface, EGL_BACK_BUFFER);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  1. Write your DirectX code to render onto 'd3dTex', and your GL code to use 'glTex'. The contents of the two textures will always match. Make sure to flush your DirectX rendering to ensure it's complete before trying to use its content in your GL scene.

Using OpenGL ES content in other DirectX rendering

This is much the same as the steps above. You have two options:

  1. Complete steps 1-3 as above. Then bind the your GL texture ('glTex') to an FBO, and render to the FBO in your GL scene. You can then use 'd3dTex' in your DirectX rendering, since the contents of 'd3dTex' and 'glTex' will always match.

  2. Complete steps 1-2 as above. Then set the surface created in Step 3 as the current surface, by calling 'eglMakeCurrent'. Then proceed to render your OpenGL ES content onto the default FBO. When complete, use 'd3dTex' to access the content in your DirectX code.

In both cases, make sure to flush your OpenGL ES content before trying to access it in DirectX, e.g. by calling glFlush().