c++opengldirectxinteropglfw

How to correctly share a texture from DX12 to OpenGL?


Under normal circumstances, creating a shared handle in DX using CreateSharedHandle, then using glImportMemoryWin32HandleEXT in OpenGL should allow sharing. I tried rendering a triangle in DX and displaying it in OpenGL. When I checked the DX output using RenderDoc, everything seemed fine, but in OpenGL, only the clearColor is displayed, and the triangle is missing. Although I suspect it might be a synchronization issue, I've already set a fence in DX. What is the correct process for sharing textures?


This is the DX output result I found in RenderDoc: enter image description here

However, the texture obtained by OpenGL looks like this: enter image description here

#include <wrl.h>
#include <windows.h>
#include "d3dx12.h"
#include <d3dcompiler.h>

#include <GL/glew.h>
#include <GLFW/glfw3.h>

#include <iostream>
#include <vector>

#define _DEBUG
//#define _DXRENDERDOC

#ifdef _DXRENDERDOC
#include "renderdoc_app.h"
#endif

using Microsoft::WRL::ComPtr;

#pragma comment(lib, "d3d12.lib")
#pragma comment(lib, "d3dcompiler.lib")
#pragma comment(lib, "opengl32.lib")
#pragma comment(lib, "glew32.lib")

ComPtr<ID3D12Device> d3d12Device;
ComPtr<ID3D12CommandQueue> commandQueue;
ComPtr<ID3D12CommandAllocator> commandAllocator;
ComPtr<ID3D12GraphicsCommandList> commandList;
ComPtr<ID3D12Fence> fence;
UINT64 fenceValue = 0;

ComPtr<ID3D12RootSignature> rootSignature;
ComPtr<ID3D12PipelineState> pipelineState;
ComPtr<ID3D12Resource> vertexBuffer;
D3D12_VERTEX_BUFFER_VIEW vertexBufferView;

HANDLE sharedHandle;
ComPtr<ID3D12Resource> sharedTexture;

GLuint glTexture;
GLuint glMemoryObject;
GLFWwindow* window;
GLuint quadVAO, quadVBO;
GLuint shaderProgram;


struct Vertex {
    float position[3];
    float color[3];
};


const char* vertexShaderSrc = R"(
struct VSInput {
    float3 position : POSITION;
    float3 color : COLOR;
};

struct PSInput {
    float4 position : SV_POSITION;
    float3 color : COLOR;
};

PSInput main(VSInput input) {
    PSInput output;
    output.position = float4(input.position, 1.0);
    output.color = input.color;
    return output;
}
)";

const char* pixelShaderSrc = R"(
struct PSInput {
    float4 position : SV_POSITION;
    float3 color : COLOR;
};

float4 main(PSInput input) : SV_TARGET {
    return float4(input.color, 1.0);
}
)";

const char* oglVertexShaderSrc = R"(
#version 450 core
layout(location = 0) in vec2 inPosition;
layout(location = 1) in vec2 inTexCoord;
out vec2 TexCoord;
void main()
{
    TexCoord = inTexCoord;
    gl_Position = vec4(inPosition, 0.0, 1.0);
}
)";

const char* oglFragmentShaderSrc = R"(
#version 450 core
in vec2 TexCoord;
out vec4 FragColor;
uniform sampler2D sharedTexture;
void main()
{
    FragColor = texture(sharedTexture, TexCoord);
}
)";

void InitD3D12();
void CreateRootSignature();
void CreateShadersAndPSO();
void CreateVertexBuffer();
void CreateSharedTexture();
void RenderTriangleToTexture();
void WaitForPreviousFrame();
void InitOpenGL();
void DisplayTexture();

void APIENTRY OpenGLDebugMessageCallback(GLenum source, GLenum type, GLuint id,
    GLenum severity, GLsizei length,
    const GLchar* message, const void* userParam)
{
    if (severity == GL_DEBUG_SEVERITY_HIGH) {
        std::cerr << "OpenGL Debug Message [" << id << "]: " << message << std::endl;
        std::cerr << "Severity: High" << std::endl;
        std::cerr << std::endl;
    }
    else if (severity == GL_DEBUG_SEVERITY_MEDIUM) {
        std::cerr << "OpenGL Debug Message [" << id << "]: " << message << std::endl;
        std::cerr << "Severity: Medium" << std::endl;
        std::cerr << std::endl;
    }
    else if (severity == GL_DEBUG_SEVERITY_LOW) {
        std::cerr << "OpenGL Debug Message [" << id << "]: " << message << std::endl;
        std::cerr << "Severity: Low" << std::endl;
        std::cerr << std::endl;
    }
    else if (severity == GL_DEBUG_SEVERITY_NOTIFICATION) {
        std::cerr << "OpenGL Debug Message [" << id << "]: " << message << std::endl;
        std::cerr << "Severity: Notification" << std::endl;
        std::cerr << std::endl;
    }
}

void InitOpenGLDebug() {
    int flags;
    glGetIntegerv(GL_CONTEXT_FLAGS, &flags);
    if (flags & GL_CONTEXT_FLAG_DEBUG_BIT) {
        std::cout << "Debug context created!" << std::endl;
    }

    glEnable(GL_DEBUG_OUTPUT);
    glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); // Ensures that errors are reported synchronously
    glDebugMessageCallback(OpenGLDebugMessageCallback, nullptr);
    glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, nullptr, GL_TRUE);
}

int main() {
    InitD3D12();
    CreateRootSignature();
    CreateShadersAndPSO();
    CreateVertexBuffer();
    CreateSharedTexture();

#ifdef _DXRENDERDOC
    RENDERDOC_API_1_0_0* rdoc_api = nullptr;
    HMODULE renderdoc_module = LoadLibraryA("renderdoc.dll");
    if (renderdoc_module) {
        pRENDERDOC_GetAPI RENDERDOC_GetAPI = (pRENDERDOC_GetAPI)GetProcAddress(renderdoc_module, "RENDERDOC_GetAPI");

        if (RENDERDOC_GetAPI) {
            int ret = RENDERDOC_GetAPI(eRENDERDOC_API_Version_1_0_0, (void**)&rdoc_api);

            if (ret == 1) {
                rdoc_api->StartFrameCapture(nullptr, nullptr);
                RenderTriangleToTexture();
                rdoc_api->EndFrameCapture(nullptr, nullptr);
            }
        }
        else {
            std::cerr << "Failed to get RenderDoc API function address." << std::endl;
        }
    }
    else {
        std::cerr << "Failed to load renderdoc.dll." << std::endl;
    }
#else
    RenderTriangleToTexture();
#endif

    InitOpenGL();

    while (!glfwWindowShouldClose(window)) {
        glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
        glClear(GL_COLOR_BUFFER_BIT);
        DisplayTexture();
        glfwSwapBuffers(window);
        glfwPollEvents();
    }

    glfwDestroyWindow(window);
    glfwTerminate();
    return 0;
}

void InitD3D12() {
#if defined(_DEBUG)
    {
        ComPtr<ID3D12Debug> debugController;
        if (SUCCEEDED(D3D12GetDebugInterface(IID_PPV_ARGS(&debugController)))) {
            debugController->EnableDebugLayer();
        }
    }
#endif

HRESULT hr = D3D12CreateDevice(
    nullptr,
    D3D_FEATURE_LEVEL_11_0,
    IID_PPV_ARGS(&d3d12Device)
);
if (FAILED(hr)) {
    std::cerr << "Failed to create D3D12 device." << std::endl;
    exit(EXIT_FAILURE);
}

D3D12_COMMAND_QUEUE_DESC queueDesc = {};
queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
d3d12Device->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&commandQueue));

d3d12Device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&commandAllocator));
d3d12Device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, commandAllocator.Get(), nullptr, IID_PPV_ARGS(&commandList));

d3d12Device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&fence));
}

void CreateRootSignature() {
    D3D12_ROOT_SIGNATURE_DESC rootSignatureDesc = {};
    rootSignatureDesc.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT;

    ComPtr<ID3DBlob> signature;
    ComPtr<ID3DBlob> error;
    HRESULT hr = D3D12SerializeRootSignature(
        &rootSignatureDesc,
        D3D_ROOT_SIGNATURE_VERSION_1,
        &signature,
        &error
    );
    if (FAILED(hr)) {
        std::cerr << "Failed to serialize root signature." << std::endl;
        exit(EXIT_FAILURE);
    }

    hr = d3d12Device->CreateRootSignature(
        0,
        signature->GetBufferPointer(),
        signature->GetBufferSize(),
        IID_PPV_ARGS(&rootSignature)
    );
    if (FAILED(hr)) {
        std::cerr << "Failed to create root signature." << std::endl;
        exit(EXIT_FAILURE);
    }
}

void CreateShadersAndPSO() {
    ComPtr<ID3DBlob> vertexShader;
    ComPtr<ID3DBlob> pixelShader;
    ComPtr<ID3DBlob> error;

    HRESULT hr = D3DCompile(
        vertexShaderSrc, strlen(vertexShaderSrc),
        nullptr, nullptr, nullptr,
        "main", "vs_5_0",
        0, 0,
        &vertexShader, &error
    );
    if (FAILED(hr)) {
        std::cerr << "Failed to compile vertex shader." << std::endl;
        if (error) {
            std::cerr << (char*)error->GetBufferPointer() << std::endl;
        }
        exit(EXIT_FAILURE);
    }

    hr = D3DCompile(
        pixelShaderSrc, strlen(pixelShaderSrc),
        nullptr, nullptr, nullptr,
        "main", "ps_5_0",
        0, 0,
        &pixelShader, &error
    );
    if (FAILED(hr)) {
        std::cerr << "Failed to compile pixel shader." << std::endl;
        if (error) {
            std::cerr << (char*)error->GetBufferPointer() << std::endl;
        }
        exit(EXIT_FAILURE);
    }

    D3D12_INPUT_ELEMENT_DESC inputElementDescs[] = {
        { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, offsetof(Vertex, position), D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
        { "COLOR",    0, DXGI_FORMAT_R32G32B32_FLOAT, 0, offsetof(Vertex, color),    D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
    };

    D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {};
    psoDesc.InputLayout = { inputElementDescs, _countof(inputElementDescs) };
    psoDesc.pRootSignature = rootSignature.Get();
    psoDesc.VS = { reinterpret_cast<BYTE*>(vertexShader->GetBufferPointer()), vertexShader->GetBufferSize() };
    psoDesc.PS = { reinterpret_cast<BYTE*>(pixelShader->GetBufferPointer()), pixelShader->GetBufferSize() };
    psoDesc.RasterizerState = CD3DX12_RASTERIZER_DESC(D3D12_DEFAULT);
    psoDesc.BlendState = CD3DX12_BLEND_DESC(D3D12_DEFAULT);
    psoDesc.DepthStencilState.DepthEnable = FALSE;
    psoDesc.DepthStencilState.StencilEnable = FALSE;
    psoDesc.SampleMask = UINT_MAX;
    psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
    psoDesc.NumRenderTargets = 1;
    psoDesc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM;
    psoDesc.SampleDesc.Count = 1;

    hr = d3d12Device->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&pipelineState));
    if (FAILED(hr)) {
        std::cerr << "Failed to create pipeline state." << std::endl;
        exit(EXIT_FAILURE);
    }
}

void CreateVertexBuffer() {
    Vertex triangleVertices[] = {
        { {  0.0f,  0.5f, 0.0f }, { 1.0f, 0.0f, 0.0f } },
        { {  0.5f, -0.5f, 0.0f }, { 0.0f, 1.0f, 0.0f } },
        { { -0.5f, -0.5f, 0.0f }, { 0.0f, 0.0f, 1.0f } },
    };

    const UINT vertexBufferSize = sizeof(triangleVertices);
    CD3DX12_HEAP_PROPERTIES heapProps(D3D12_HEAP_TYPE_UPLOAD);
    CD3DX12_RESOURCE_DESC bufferDesc = CD3DX12_RESOURCE_DESC::Buffer(vertexBufferSize);

    HRESULT hr = d3d12Device->CreateCommittedResource(
        &heapProps,
        D3D12_HEAP_FLAG_NONE,
        &bufferDesc,
        D3D12_RESOURCE_STATE_GENERIC_READ,
        nullptr,
        IID_PPV_ARGS(&vertexBuffer)
    );
    if (FAILED(hr)) {
        std::cerr << "Failed to create vertex buffer." << std::endl;
        exit(EXIT_FAILURE);
    }

    UINT8* vertexDataBegin;
    CD3DX12_RANGE readRange(0, 0);
    vertexBuffer->Map(0, &readRange, reinterpret_cast<void**>(&vertexDataBegin));
    memcpy(vertexDataBegin, triangleVertices, sizeof(triangleVertices));
    vertexBuffer->Unmap(0, nullptr);

    vertexBufferView.BufferLocation = vertexBuffer->GetGPUVirtualAddress();
    vertexBufferView.StrideInBytes = sizeof(Vertex);
    vertexBufferView.SizeInBytes = vertexBufferSize;
}

void CreateSharedTexture() {
    D3D12_RESOURCE_DESC textureDesc = {};
    textureDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
    textureDesc.Width = 512;
    textureDesc.Height = 512;
    textureDesc.DepthOrArraySize = 1;
    textureDesc.MipLevels = 1;
    textureDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
    textureDesc.SampleDesc.Count = 1;
    textureDesc.SampleDesc.Quality = 0;
    textureDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
    textureDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;

    D3D12_HEAP_PROPERTIES heapProps = {};
    heapProps.Type = D3D12_HEAP_TYPE_DEFAULT;

    D3D12_CLEAR_VALUE clearValue = {};
    clearValue.Format = textureDesc.Format;
    clearValue.Color[0] = 0.0f;
    clearValue.Color[1] = 0.0f;
    clearValue.Color[2] = 0.0f;
    clearValue.Color[3] = 1.0f;

    HRESULT hr = d3d12Device->CreateCommittedResource(
        &heapProps,
        D3D12_HEAP_FLAG_SHARED,
        &textureDesc,
        D3D12_RESOURCE_STATE_COMMON,
        &clearValue,
        IID_PPV_ARGS(&sharedTexture)
    );
    if (FAILED(hr)) {
        std::cerr << "Failed to create shared texture." << std::endl;
        exit(EXIT_FAILURE);
    }

    hr = d3d12Device->CreateSharedHandle(
        sharedTexture.Get(),
        nullptr,
        GENERIC_ALL,
        nullptr,
        &sharedHandle
    );
    if (FAILED(hr)) {
        std::cerr << "Failed to create shared handle." << std::endl;
        exit(EXIT_FAILURE);
    }
}

void RenderTriangleToTexture() {
    WaitForPreviousFrame();

    commandAllocator->Reset();
    commandList->Reset(commandAllocator.Get(), pipelineState.Get());
    commandList->SetGraphicsRootSignature(rootSignature.Get());
    D3D12_VIEWPORT viewport;
    viewport.TopLeftX = 0;
    viewport.TopLeftY = 0;
    viewport.Width = 512;
    viewport.Height = 512;
    viewport.MinDepth = 0.0f;
    viewport.MaxDepth = 1.0f;
    commandList->RSSetViewports(1, &viewport);
    D3D12_RECT scissorRect = { 0, 0, 512, 512 };
    commandList->RSSetScissorRects(1, &scissorRect);

    D3D12_RESOURCE_BARRIER ctBarrier = CD3DX12_RESOURCE_BARRIER::Transition(
        sharedTexture.Get(),
        D3D12_RESOURCE_STATE_COMMON,
        D3D12_RESOURCE_STATE_RENDER_TARGET);
    commandList->ResourceBarrier(1, &ctBarrier);

    D3D12_DESCRIPTOR_HEAP_DESC rtvHeapDesc = {};
    rtvHeapDesc.NumDescriptors = 1;
    rtvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
    rtvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;

    ComPtr<ID3D12DescriptorHeap> rtvHeap;
    d3d12Device->CreateDescriptorHeap(&rtvHeapDesc, IID_PPV_ARGS(&rtvHeap));

    D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = rtvHeap->GetCPUDescriptorHandleForHeapStart();
    d3d12Device->CreateRenderTargetView(sharedTexture.Get(), nullptr, rtvHandle);

    commandList->OMSetRenderTargets(1, &rtvHandle, FALSE, nullptr);

    const float clearColor[] = { 1.0f, 0.2f, 0.4f, 1.0f };
    commandList->ClearRenderTargetView(rtvHandle, clearColor, 0, nullptr);

    commandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
    commandList->IASetVertexBuffers(0, 1, &vertexBufferView);

    commandList->DrawInstanced(3, 1, 0, 0);

    D3D12_RESOURCE_BARRIER tcBarrier = CD3DX12_RESOURCE_BARRIER::Transition(
        sharedTexture.Get(),
        D3D12_RESOURCE_STATE_RENDER_TARGET,
        D3D12_RESOURCE_STATE_COMMON);
    commandList->ResourceBarrier(1, &tcBarrier);

    commandList->Close();
    ID3D12CommandList* commandLists[] = { commandList.Get() };
    commandQueue->ExecuteCommandLists(_countof(commandLists), commandLists);

    WaitForPreviousFrame();
}

void WaitForPreviousFrame() {
    fenceValue++;
    commandQueue->Signal(fence.Get(), fenceValue);

    if (fence->GetCompletedValue() < fenceValue) {
        HANDLE eventHandle = CreateEventEx(nullptr, nullptr, false, EVENT_ALL_ACCESS);
        fence->SetEventOnCompletion(fenceValue, eventHandle);
        WaitForSingleObject(eventHandle, INFINITE);
        CloseHandle(eventHandle);
    }
}

void InitOpenGL() {
    if (!glfwInit()) {
        std::cerr << "Failed to initialize GLFW." << std::endl;
        exit(EXIT_FAILURE);
    }

    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GLFW_TRUE);

    window = glfwCreateWindow(512, 512, "OpenGL Window", nullptr, nullptr);
    if (!window) {
        std::cerr << "Failed to create GLFW window." << std::endl;
        glfwTerminate();
        exit(EXIT_FAILURE);
    }
    glfwMakeContextCurrent(window);

    glewExperimental = GL_TRUE;
    GLenum glewInitResult = glewInit();
    if (GLEW_OK != glewInitResult) {
        std::cerr << "Failed to initialize GLEW: "
            << glewGetErrorString(glewInitResult) << std::endl;
        exit(EXIT_FAILURE);
    }

    InitOpenGLDebug();

    if (!GLEW_EXT_memory_object || !GLEW_EXT_memory_object_win32) {
        std::cerr << "Required OpenGL extensions are not supported." << std::endl;
        exit(EXIT_FAILURE);
    }

    glCreateMemoryObjectsEXT(1, &glMemoryObject);

    D3D12_PLACED_SUBRESOURCE_FOOTPRINT layout;
    UINT64 totalSize;
    D3D12_RESOURCE_DESC resourceDisc = sharedTexture->GetDesc();
    d3d12Device->GetCopyableFootprints(&resourceDisc, 0, 1, 0, &layout, nullptr, nullptr, &totalSize);

    // If the memory size isn't `width*height*4` due to DX alignment, setting this doesn't help, which is quite frustrating.
    // UINT rowPitch = layout.Footprint.RowPitch;
    // glPixelStorei(GL_UNPACK_ROW_LENGTH, rowPitch / 4);

    if (!GLEW_EXT_memory_object || !GLEW_EXT_memory_object_win32) {
        std::cerr << "Required OpenGL extensions are not supported." << std::endl;
        exit(EXIT_FAILURE);
    }

    glImportMemoryWin32HandleEXT(glMemoryObject, totalSize, GL_HANDLE_TYPE_D3D12_RESOURCE_EXT, sharedHandle);

    glGenTextures(1, &glTexture);

    glBindTexture(GL_TEXTURE_2D, glTexture);
    glTexStorageMem2DEXT(GL_TEXTURE_2D, 1, GL_RGBA8, 512, 512, glMemoryObject, 0);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

    GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertexShader, 1, &oglVertexShaderSrc, nullptr);
    glCompileShader(vertexShader);

    GLint success;
    glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
    if (!success) {
        char infoLog[512];
        glGetShaderInfoLog(vertexShader, 512, nullptr, infoLog);
        std::cerr << "Failed to compile OpenGL vertex shader:\n" << infoLog << std::endl;
        exit(EXIT_FAILURE);
    }

    GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragmentShader, 1, &oglFragmentShaderSrc, nullptr);
    glCompileShader(fragmentShader);

    glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
    if (!success) {
        char infoLog[512];
        glGetShaderInfoLog(fragmentShader, 512, nullptr, infoLog);
        std::cerr << "Failed to compile OpenGL fragment shader:\n" << infoLog << std::endl;
        exit(EXIT_FAILURE);
    }


    shaderProgram = glCreateProgram();
    glAttachShader(shaderProgram, vertexShader);
    glAttachShader(shaderProgram, fragmentShader);
    glLinkProgram(shaderProgram);

    glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
    if (!success) {
        char infoLog[512];
        glGetProgramInfoLog(shaderProgram, 512, nullptr, infoLog);
        std::cerr << "Failed to link OpenGL shader program:\n" << infoLog << std::endl;
        exit(EXIT_FAILURE);
    }


    glDeleteShader(vertexShader);
    glDeleteShader(fragmentShader);

    float quadVertices[] = {
        // Positions    // Texture Coords
        -1.0f,  1.0f,    0.0f, 0.0f, // Top-left
        -1.0f, -1.0f,    0.0f, 1.0f, // Bottom-left
         1.0f, -1.0f,    1.0f, 1.0f, // Bottom-right

        -1.0f,  1.0f,    0.0f, 0.0f, // Top-left
         1.0f, -1.0f,    1.0f, 1.0f, // Bottom-right
         1.0f,  1.0f,    1.0f, 0.0f  // Top-right
    };

    glGenVertexArrays(1, &quadVAO);
    glGenBuffers(1, &quadVBO);
    glBindVertexArray(quadVAO);

    glBindBuffer(GL_ARRAY_BUFFER, quadVBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(quadVertices), quadVertices, GL_STATIC_DRAW);

    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);

    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)(2 * sizeof(float)));
    glEnableVertexAttribArray(1);

    glBindVertexArray(0);
    glUseProgram(shaderProgram);
    glUniform1i(glGetUniformLocation(shaderProgram, "sharedTexture"), 0);
}

void DisplayTexture() {
    glUseProgram(shaderProgram);

    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, glTexture);

    glBindVertexArray(quadVAO);
    glDrawArrays(GL_TRIANGLES, 0, 6);
    glBindVertexArray(0);
}

Solution

  • I found that the issue was caused by me not closing the command list after creating it.

    +#232 commandList->Close();
    

    And according to the description in How to use glImportMemoryWin32HandleEXT, the size when importing should be twice the total size.

    #529 glImportMemoryWin32HandleEXT(glMemoryObject, totalSize * 2, GL_HANDLE_TYPE_D3D12_RESOURCE_EXT, sharedHandle);