Troubleshooting Black Screen Output on DisplayPort for Offscreen Rendering with EGLStream on Ubuntu 22.04 (NVIDIA 4090 D, AMD Chipset)

My work environment is Ubuntu 22.04, using an NVIDIA 4090 D GPU with an AMD chipset.

I aim to directly transfer offscreen-rendered content to the DisplayPort interface via EGLStream for display.

Currently, I have successfully initialized DRM and selected the corresponding CRTC. I created a buffer in GPU memory through GBM, bound it to the CRTC, and then retrieved the output layer associated with the CRTC, which I successfully bound to the EGLStream consumer. After that, I created a PSurface and bound it as the producer.

The rendered content appears correct when checked with glReadPixels.

After calling eglSwapBuffers, the stream status is EGL_STREAM_STATE_NEW_FRAME_AVAILABLE_KHR, but the display connected to the DisplayPort still shows a black screen.

Could you help identify the possible cause of this issue?"

// Function to print EGLStream state
void printEglStreamState(EGLDisplay eglDpy, EGLStreamKHR eglStream, PFNEGLQUERYSTREAMKHRPROC eglQueryStreamKHR) {
    EGLint streamState;
    if (eglQueryStreamKHR(eglDpy, eglStream, EGL_STREAM_STATE_KHR, &streamState)) {
        std::cout << "EGLStream State: ";
        switch (streamState) {
            case EGL_STREAM_STATE_CREATED_KHR:
                std::cout << "EGL_STREAM_STATE_CREATED_KHR" << std::endl;
                break;
            case EGL_STREAM_STATE_CONNECTING_KHR:
                std::cout << "EGL_STREAM_STATE_CONNECTING_KHR" << std::endl;
                break;
            case EGL_STREAM_STATE_EMPTY_KHR:
                std::cout << "EGL_STREAM_STATE_EMPTY_KHR" << std::endl;
                break;
            case EGL_STREAM_STATE_NEW_FRAME_AVAILABLE_KHR:
                std::cout << "EGL_STREAM_STATE_NEW_FRAME_AVAILABLE_KHR" << std::endl;
                break;
            case EGL_STREAM_STATE_OLD_FRAME_AVAILABLE_KHR:
                std::cout << "EGL_STREAM_STATE_OLD_FRAME_AVAILABLE_KHR" << std::endl;
                break;
            case EGL_STREAM_STATE_DISCONNECTED_KHR:
                std::cout << "EGL_STREAM_STATE_DISCONNECTED_KHR" << std::endl;
                break;
            default:
                std::cout << "Unknown State (0x" << std::hex << streamState << ")" << std::endl;
        }
    } else {
        EGLint error = eglGetError();
        std::cerr << "Failed to query EGLStream state. EGL Error: 0x" << std::hex << error << std::endl;
    }
}

// Function to check EGL errors
void checkEglError(const std::string& msg) {
    EGLint error = eglGetError();
    if (error != EGL_SUCCESS) {
        std::cerr << "EGL error after " << msg << ": 0x" << std::hex << error << std::endl;
        throw std::runtime_error("EGL error occurred");
    }
}

void checkGlError(const std::string& msg) {
    GLenum error = glGetError();
    if (error != GL_NO_ERROR) {
        std::cerr << "OpenGL error after " << msg << ": 0x" << std::hex << error << std::endl;
        throw std::runtime_error("OpenGL error occurred");
    }
}


struct gbm_bo* createGbmFramebuffer(int drm_fd, gbm_device* gbm, uint32_t* fb_id, uint32_t* width, uint32_t* height, uint32_t* handle) {
    // Create GBM buffer object
    std::cout << "Creating GBM buffer object with width=" << *width << " and height=" << *height << std::endl;

    // Use AR24 (GBM_FORMAT_ARGB8888)
    uint64_t modifiers[] = { DRM_FORMAT_MOD_LINEAR };
    struct gbm_bo* bo = gbm_bo_create_with_modifiers(gbm, *width, *height,
                                                     GBM_FORMAT_XRGB8888,
                                                     modifiers, 1);
    if (!bo) {
        std::cerr << "Failed to create GBM buffer object with modifiers: " << strerror(errno) << std::endl;
        exit(EXIT_FAILURE);
    }

    uint64_t modifier = gbm_bo_get_modifier(bo);

    // Get buffer handle and stride
    gbm_bo_handle bo_handle = gbm_bo_get_handle(bo);
    if (!bo_handle.u32) {
        std::cerr << "Failed to get GBM buffer handle" << std::endl;
        gbm_bo_destroy(bo);
        exit(EXIT_FAILURE);
    }
    *handle = bo_handle.u32;
    uint32_t stride = gbm_bo_get_stride(bo);
    std::cout << "GBM buffer object created. Handle=" << *handle << ", stride=" << stride << std::endl;

    // Add framebuffer using drmModeAddFB2 for better format handling
    uint32_t handles[4] = { *handle, 0, 0, 0 };
    uint32_t pitches[4] = { stride, 0, 0, 0 };
    uint32_t offsets[4] = { 0, 0, 0, 0 };
    uint64_t modifiers_array[4] = { modifier, 0, 0, 0 };

    int ret = drmModeAddFB2WithModifiers(drm_fd, *width, *height, GBM_FORMAT_XRGB8888,
                                         handles, pitches, offsets, modifiers_array, fb_id, DRM_MODE_FB_MODIFIERS);
    if (ret) {
        std::cerr << "Failed to add framebuffer using drmModeAddFB2WithModifiers: " << strerror(errno) << std::endl;
        gbm_bo_destroy(bo);
        exit(EXIT_FAILURE);
    }


    std::cout << "Framebuffer successfully created: fb_id=" << *fb_id
              << ", width=" << *width << ", height=" << *height << std::endl;
    return bo;
}



void setCrtcForDP(int drm_fd, drmModeRes* resources, drmModeConnector* connector, uint32_t fb_id, uint32_t width, uint32_t height, uint32_t& crtc_id) {
    drmModeEncoder* encoder = nullptr;

    if (connector->encoder_id) {
        encoder = drmModeGetEncoder(drm_fd, connector->encoder_id);
    }

    if (!encoder) {
        for (int i = 0; i < resources->count_encoders; ++i) {
            encoder = drmModeGetEncoder(drm_fd, resources->encoders[i]);
            if (encoder && (encoder->possible_crtcs & (1 << i))) {
                break;
            }
            drmModeFreeEncoder(encoder);
            encoder = nullptr;
        }
    }

    if (!encoder) {
        std::cerr << "Failed to find a suitable encoder, exiting..." << std::endl;
        exit(EXIT_FAILURE);
    }

    drmModeCrtc* crtc = nullptr;
    for (int i = 0; i < resources->count_crtcs; ++i) {
        if (encoder->possible_crtcs & (1 << i)) {
            crtc = drmModeGetCrtc(drm_fd, resources->crtcs[i]);
            if (crtc) {
                crtc_id = crtc->crtc_id;
                std::cout << "crtc_id = " << crtc->crtc_id << std::endl;
                break;
            }
        }
    }

    if (!crtc) {
        std::cerr << "Failed to find a suitable CRTC, exiting..." << std::endl;
        drmModeFreeEncoder(encoder);
        exit(EXIT_FAILURE);
    }

    drmModeModeInfo mode = connector->modes[3];  // Use first mode (1920x1080 @ 60Hz)
    std::cout << "Trying mode 3: " << mode.hdisplay << "x" << mode.vdisplay << "@" << mode.vrefresh << "Hz" << std::endl;

    if (drmModeSetCrtc(drm_fd, crtc->crtc_id, fb_id, 0, 0, &connector->connector_id, 1, &mode) < 0) {
        std::cerr << "Failed to set CRTC: " << strerror(errno) << std::endl;
        drmModeFreeEncoder(encoder);
        drmModeFreeCrtc(crtc);  // 确保释放 CRTC
    } else {
        std::cout << "Successfully set CRTC with framebuffer." << std::endl;
    }
}


const char* vertexShaderSource = 
    "#version 330 core\n"
    "layout (location = 0) in vec3 aPos;\n"
    "void main()\n"
    "{\n"
    "    gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
    "}\n";

const char* fragmentShaderSource =
    "#version 330 core\n"
    "out vec4 FragColor;\n"
    "void main()\n"
    "{\n"
    "    FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n"
    "}\n";


int main() {
    try {

        // int drm_fd = open("/dev/dri/card2", O_RDWR | O_CLOEXEC);
        // if (drm_fd < 0) {
        //     std::cerr << "Failed to open DRM device" << std::endl;
        //     return -1;
        // }

        

        // 初始化 EGL 和选择 GPU 使用 EGLStream 扩展
        static const EGLint configAttribs[] = {
            EGL_SURFACE_TYPE, EGL_STREAM_BIT_KHR | EGL_PBUFFER_BIT, // 支持 Stream 和 Pbuffer
            EGL_BLUE_SIZE, 8,
            EGL_GREEN_SIZE, 8,
            EGL_RED_SIZE, 8,
            EGL_ALPHA_SIZE, 8, // 添加 alpha 通道
            EGL_DEPTH_SIZE, 24,
            EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
            EGL_COLOR_BUFFER_TYPE, EGL_RGB_BUFFER, // 指定颜色缓冲区类型
            EGL_NONE
        };

        // 加载必要的 EGL 扩展函数
        PFNEGLQUERYDEVICESEXTPROC eglQueryDevicesEXT = (PFNEGLQUERYDEVICESEXTPROC)eglGetProcAddress("eglQueryDevicesEXT");
        PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT = (PFNEGLGETPLATFORMDISPLAYEXTPROC)eglGetProcAddress("eglGetPlatformDisplayEXT");
        PFNEGLQUERYDEVICESTRINGEXTPROC eglQueryDeviceStringEXT = (PFNEGLQUERYDEVICESTRINGEXTPROC)eglGetProcAddress("eglQueryDeviceStringEXT");

        if (!eglQueryDevicesEXT || !eglGetPlatformDisplayEXT || !eglQueryDeviceStringEXT) {
            std::cerr << "Failed to get EGL device extensions" << std::endl;
            return -1;
        }

        // 查询所有可用设备
        const int maxDevices = 10;
        EGLDeviceEXT eglDevices[maxDevices];
        EGLint numDevices;
        if (!eglQueryDevicesEXT(maxDevices, eglDevices, &numDevices)) {
            std::cerr << "Failed to query EGL devices." << std::endl;
            return -1;
        }

        if (numDevices < 1) {
            std::cerr << "No EGL devices found" << std::endl;
            return -1;
        }

        std::cout << "Found " << numDevices << " devices" << std::endl;

        const char *clientExtensionString = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);

        if (strstr(clientExtensionString, "EGL_EXT_device_base") == nullptr) {
            std::cerr << "EGL_EXT_device_base extension is not supported." << std::endl;
            return -1;
        } else {
            std::cout << "EGL_EXT_device_base extension is supported." << std::endl;
        }

        if (strstr(clientExtensionString, "EGL_EXT_device_enumeration") == nullptr) {
            std::cerr << "EGL_EXT_device_enumeration extension is not supported." << std::endl;
            return -1;
        } else {
            std::cout << "EGL_EXT_device_enumeration extension is supported." << std::endl;
        }

        if (strstr(clientExtensionString, "EGL_EXT_device_query") == nullptr) {
            std::cerr << "EGL_EXT_device_query extension is not supported." << std::endl;
            return -1;
        } else {
            std::cout << "EGL_EXT_device_query extension is supported." << std::endl;
        }

        // EGL_NO_DEVICE_EXT
        EGLDeviceEXT eglDevice = EGL_NO_DEVICE_EXT;

        for (int i = 0; i < numDevices; ++i)
        {
            const char *deviceExtensionString = eglQueryDeviceStringEXT(eglDevices[i], EGL_EXTENSIONS);

            if (strstr(deviceExtensionString, "EGL_EXT_device_drm") == nullptr) {
                std::cerr << "EGL_EXT_device_drm extension is not supported." << std::endl;
                return -1;
            } else {
                std::cout << "EGL_EXT_device_drm extension is supported." << std::endl;
                eglDevice = eglDevices[i];
                break;
            }

        }
    
        if (eglDevice == EGL_NO_DEVICE_EXT) {
            std::cerr << "No EGL_EXT_device_drm-capable EGL device found." << std::endl;
            return -1;
        }

        const char *drmDeviceFile;
        drmDeviceFile = eglQueryDeviceStringEXT(eglDevice, EGL_DRM_DEVICE_FILE_EXT);

        if (drmDeviceFile == NULL) {
            std::cerr << "No DRM device file found for EGL device.\n";
            return -1;
        }

        std::cout << "Supported EGL drmDeviceFile:" << std::endl;
        std::cout << drmDeviceFile << std::endl;

        int drm_fd = open(drmDeviceFile, O_RDWR | O_CLOEXEC, 0);
        if (drm_fd < 0) {
            std::cerr << "Failed to open DRM device" << std::endl;
            return -1;
        }else{
            std::cout << "drm_fd = " << drm_fd << std::endl;
        }

        // 检查是否为 DRM Master
        if (drmIsMaster(drm_fd)) {
            std::cout << "DRM 文件描述符拥有 DRM Master 权限。" << std::endl;
        } else {
            std::cout << "DRM 文件描述符没有 DRM Master 权限,尝试获取..." << std::endl;
            
            // 尝试获取 DRM Master 权限
            int ret = drmSetMaster(drm_fd);
            if (ret == 0) {
                std::cout << "成功获取 DRM Master 权限。" << std::endl;
            } else {
                std::cerr << "无法获取 DRM Master 权限:" << strerror(errno) << std::endl;
                // 根据需要处理错误,例如退出程序或重试
            }
        }

        drmModeRes* resources = drmModeGetResources(drm_fd);
        if (!resources) {
            std::cerr << "Failed to get DRM resources" << std::endl;
            return -1;
        }

        drmModeConnector* connector = nullptr;

        for (int i = 0; i < resources->count_connectors; ++i) {
            connector = drmModeGetConnector(drm_fd, resources->connectors[i]);
            if (connector->connection == DRM_MODE_CONNECTED && 
                connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort) {
                std::cout << "Connected to DP-1" << std::endl;
                break;
            }
            drmModeFreeConnector(connector);
            connector = nullptr;
        }

        if (!connector) {
            std::cerr << "No connected DisplayPort found" << std::endl;
            return -1;
        }

        const int WIDTH = 1920;
        const int HEIGHT = 1080;

        // Setup GBM device and framebuffer
        gbm_device* gbm = gbm_create_device(drm_fd);
        uint32_t fb_id_1 = 0, width = WIDTH, height = HEIGHT, handle_1 = 0;
        uint32_t fb_id_2 = 0, handle_2 = 0;

        struct gbm_bo* bo_1 = createGbmFramebuffer(drm_fd, gbm, &fb_id_1, &width, &height, &handle_1);
        struct gbm_bo* bo_2 = createGbmFramebuffer(drm_fd, gbm, &fb_id_2, &width, &height, &handle_2);

        std::cout << "fb_id_1 = " << fb_id_1 << std::endl;
        std::cout << "fb_id_2 = " << fb_id_2 << std::endl;

        uint32_t stride_1;
        void *map_data_1;
        void *mapped_buffer_1 = gbm_bo_map(bo_1, 0, 0, WIDTH, HEIGHT, GBM_BO_TRANSFER_WRITE, &stride_1, &map_data_1);
        if (!mapped_buffer_1) {
            std::cerr << "Failed to map GBM buffer 1" << std::endl;
            return -1;
        }

        uint32_t stride_2;
        void *map_data_2;
        void *mapped_buffer_2 = gbm_bo_map(bo_2, 0, 0, WIDTH, HEIGHT, GBM_BO_TRANSFER_WRITE, &stride_2, &map_data_2);
        if (!mapped_buffer_2) {
            std::cerr << "Failed to map GBM buffer 2" << std::endl;
            return -1;
        }


        /*
         * eglGetPlatformDisplayEXT requires EGL client extension
         * EGL_EXT_platform_base.
         */
        if (strstr(clientExtensionString, "EGL_EXT_platform_base") == nullptr) {
            std::cerr << "EGL_EXT_platform_base extension is not supported." << std::endl;
            return -1;
        } else {
            std::cout << "EGL_EXT_platform_base extension is supported." << std::endl;
        }

        /*
         * EGL_EXT_platform_device is required to pass
         * EGL_PLATFORM_DEVICE_EXT to eglGetPlatformDisplayEXT().
         */
        if (strstr(clientExtensionString, "EGL_EXT_platform_device") == nullptr) {
            std::cerr << "EGL_EXT_platform_device extension is not supported." << std::endl;
            return -1;
        } else {
            std::cout << "EGL_EXT_platform_device extension is supported." << std::endl;
        }



        EGLint dispAttribs[] = {
            EGL_DRM_MASTER_FD_EXT,
            drm_fd,
            EGL_NONE
        };
        EGLDisplay eglDpy = eglGetPlatformDisplayEXT(EGL_PLATFORM_DEVICE_EXT, eglDevice, dispAttribs);
        if (eglDpy == EGL_NO_DISPLAY) {
            std::cerr << "Failed to get EGL display from device" << std::endl;
            return -1;
        }

        // 初始化 display
        EGLint major, minor;
        if (!eglInitialize(eglDpy, &major, &minor)) {
            checkEglError("eglInitialize");
        }
        std::cout << "EGL initialized, version " << major << "." << minor << std::endl;

        if (!eglBindAPI(EGL_OPENGL_API)) {
            checkEglError("eglBindAPI");
        }
        std::cout << "EGL_OPENGL_API bound." << std::endl;



        // 查询所有支持的 EGL 扩展
        const char* extensions = eglQueryString(eglDpy, EGL_EXTENSIONS);
        if (extensions == nullptr) {
            std::cerr << "Failed to query EGL extensions" << std::endl;
            return -1;
        }

        // 打印扩展列表
        std::cout << "Supported EGL extensions:" << std::endl;
        std::cout << extensions << std::endl;


        // 检查是否支持 EGL_KHR_stream 扩展
        if (strstr(extensions, "EGL_KHR_stream") == nullptr) {
            std::cerr << "EGL_KHR_stream extension is not supported." << std::endl;
            return -1;
        } else {
            std::cout << "EGL_KHR_stream extension is supported." << std::endl;
        }

        /*
         * EGL_EXT_output_base and EGL_EXT_output_drm are needed to find
         * the EGLOutputLayer for the DRM KMS plane.
         */

        if (strstr(extensions, "EGL_EXT_output_base") == nullptr) {
            std::cerr << "EGL_EXT_output_base extension is not supported." << std::endl;
            return -1;
        } else {
            std::cout << "EGL_EXT_output_base extension is supported." << std::endl;
        }

        if (strstr(extensions, "EGL_EXT_output_drm") == nullptr) {
            std::cerr << "EGL_EXT_output_drm extension is not supported." << std::endl;
            return -1;
        } else {
            std::cout << "EGL_EXT_output_drm extension is supported." << std::endl;
        }

        /*
         * EGL_KHR_stream, EGL_EXT_stream_consumer_egloutput, and
         * EGL_KHR_stream_producer_eglsurface are needed to create an
         * EGLStream connecting an EGLSurface and an EGLOutputLayer.
         */

        if (strstr(extensions, "EGL_EXT_stream_consumer_egloutput") == nullptr) {
            std::cerr << "EGL_EXT_stream_consumer_egloutput extension is not supported." << std::endl;
            return -1;
        } else {
            std::cout << "EGL_EXT_stream_consumer_egloutput extension is supported." << std::endl;
        }

        if (strstr(extensions, "EGL_KHR_stream_producer_eglsurface") == nullptr) {
            std::cerr << "EGL_KHR_stream_producer_eglsurface extension is not supported." << std::endl;
            return -1;
        } else {
            std::cout << "EGL_KHR_stream_producer_eglsurface extension is supported." << std::endl;
        }


        // 选择第一个符合要求的 EGL 配置
        EGLint numConfigs;
        EGLConfig eglCfg;
        if (!eglChooseConfig(eglDpy, configAttribs, &eglCfg, 1, &numConfigs) || numConfigs == 0) {
            checkEglError("eglChooseConfig");
        }
        std::cout << "EGLConfig chosen successfully." << std::endl;

        // 验证 EGLConfig 是否支持 streams
        EGLint surfaceType;
        if (!eglGetConfigAttrib(eglDpy, eglCfg, EGL_SURFACE_TYPE, &surfaceType)) {
            checkEglError("eglGetConfigAttrib");
        }
        if (!(surfaceType & EGL_STREAM_BIT_KHR)) {
            std::cerr << "EGLConfig does not support streams." << std::endl;
            return -1;
        } else {
            std::cout << "EGLConfig supports streams." << std::endl;
        }

        // 加载 EGLStream 函数
        loadEglStreamFunctions();
        std::cout << "EGLStream functions loaded successfully." << std::endl;

        // 创建 EGLStream
        const EGLint streamAttribs[] = {
            EGL_CONSUMER_LATENCY_USEC_KHR, 0,      // 低延迟
            EGL_STREAM_FIFO_LENGTH_KHR, 1,         // 指定最多4个缓冲区
            EGL_NONE
        };

        EGLStreamKHR eglStream = eglCreateStreamKHR(eglDpy, streamAttribs);
        if (eglStream == EGL_NO_STREAM_KHR) {
            checkEglError("eglCreateStreamKHR");
        } else {
            std::cout << "EGLStream created successfully: " << eglStream << std::endl;
        }

        // 查询所有可用的 Output Layers(Consumer)
        EGLint numLayers = 0;
        EGLAttrib layerAttribs[] = { EGL_NONE };
        if (!eglGetOutputLayersEXT(eglDpy, layerAttribs, nullptr, 0, &numLayers)) {
            std::cerr << "Failed to get number of output layers." << std::endl;
            return -1;
        }

        if (numLayers == 0) {
            throw std::runtime_error("No available output layers found for DisplayPort");
        }

        std::cout << "Found " << numLayers << " available output layers." << std::endl;

        // 分配空间并查询 Output Layers
        EGLOutputLayerEXT* eglOutputLayers = new EGLOutputLayerEXT[numLayers];
        if (!eglGetOutputLayersEXT(eglDpy, layerAttribs, eglOutputLayers, numLayers, &numLayers)) {
            std::cerr << "Failed to get output layers." << std::endl;
            delete[] eglOutputLayers;
            return -1;
        }

        // 打印并查询每个 Output Layer 的属性
        for (int i = 0; i < numLayers; ++i) {
            EGLOutputLayerEXT layer = eglOutputLayers[i];
            std::cout << "Output Layer " << i << ": " << layer << std::endl;

            EGLAttrib crtc_id;
            if (eglQueryOutputLayerAttribEXT(eglDpy, layer, EGL_DRM_CRTC_EXT, &crtc_id)) {
                std::cout << "  CRTC ID: " << crtc_id << std::endl;
            } else {
                std::cerr << "  Failed to query CRTC ID for Output Layer " << i << std::endl;
            }

            EGLAttrib format;
            if (eglQueryOutputLayerAttribEXT(eglDpy, layer, EGL_RENDER_BUFFER, &format)) { // 使用标准 EGL_RENDER_BUFFER
                std::cout << "  Render Buffer Format: " << format << std::endl;
            } else {
                std::cerr << "  Failed to query Render Buffer Format for Output Layer " << i << std::endl;
            }

            // 其他属性查询(根据需要)
        }

        // 选择第一个 Output Layer 作为 Consumer
        EGLOutputLayerEXT eglOutputLayer = eglOutputLayers[0];
        std::cout << "Using Output Layer " << 0 << " as Consumer." << std::endl;

        // 绑定 EGLStream 到 Output Layer(Consumer)
        if (!eglStreamConsumerOutputEXT(eglDpy, eglStream, eglOutputLayer)) {
            checkEglError("eglStreamConsumerOutputEXT");
        } else {
            std::cout << "Successfully bound EGLStream to the output layer." << std::endl;
        }

        uint32_t crtc_id = 0;
        setCrtcForDP(drm_fd, resources, connector, fb_id_1, width, height, crtc_id);

        // 创建 Producer Surface
        const EGLint surfaceAttribs[] = {
            EGL_WIDTH, 1920,
            EGL_HEIGHT, 1080,
            EGL_NONE
        };

        EGLSurface eglSurf = eglCreateStreamProducerSurfaceKHR(eglDpy, eglCfg, eglStream, surfaceAttribs);
        if (eglSurf == EGL_NO_SURFACE) {
            EGLint error = eglGetError();
            std::cerr << "Failed to create stream producer surface. EGL Error: 0x" << std::hex << error << std::endl;
            throw std::runtime_error("eglCreateStreamProducerSurfaceKHR failed");
        } else {
            std::cout << "EGLStream producer surface created successfully: " << eglSurf << std::endl;
        }

        // 创建 OpenGL 上下文
        EGLint contextAttribs[] = {
            EGL_CONTEXT_MAJOR_VERSION, 3,
            EGL_CONTEXT_MINOR_VERSION, 0,
            EGL_NONE
        };
        EGLContext eglContext = eglCreateContext(eglDpy, eglCfg, EGL_NO_CONTEXT, contextAttribs);
        if (eglContext == EGL_NO_CONTEXT) {
            checkEglError("eglCreateContext");
        }

        // 绑定上下文到 Producer Surface
        if (!eglMakeCurrent(eglDpy, eglSurf, eglSurf, eglContext)) {
            checkEglError("eglMakeCurrent for Producer Surface");
        } else {
            std::cout << "EGLContext bound to producer surface successfully." << std::endl;
        }

        // 加载 OpenGL 函数
        loadOpenGLFunctions();
        std::cout << "OpenGL functions loaded successfully." << std::endl;


        // 编译着色器并渲染
        GLuint vertex, fragment;
        vertex = glCreateShader(GL_VERTEX_SHADER);
        glShaderSource(vertex, 1, &vertexShaderSource, nullptr);
        glCompileShader(vertex);
        GLint success;
        glGetShaderiv(vertex, GL_COMPILE_STATUS, &success);
        if (!success) {
            char infoLog[512];
            glGetShaderInfoLog(vertex, 512, nullptr, infoLog);
            std::cerr << "Vertex shader compilation failed: " << infoLog << std::endl;
            return -1;
        }
        checkGlError("glCompileShader (vertex)");

        fragment = glCreateShader(GL_FRAGMENT_SHADER);
        glShaderSource(fragment, 1, &fragmentShaderSource, nullptr);
        glCompileShader(fragment);
        glGetShaderiv(fragment, GL_COMPILE_STATUS, &success);
        if (!success) {
            char infoLog[512];
            glGetShaderInfoLog(fragment, 512, nullptr, infoLog);
            std::cerr << "Fragment shader compilation failed: " << infoLog << std::endl;
            return -1;
        }
        checkGlError("glCompileShader (fragment)");

        GLuint program = glCreateProgram();
        glAttachShader(program, vertex);
        glAttachShader(program, fragment);
        glLinkProgram(program);
        glGetProgramiv(program, GL_LINK_STATUS, &success);
        if (!success) {
            char infoLog[512];
            glGetProgramInfoLog(program, 512, nullptr, infoLog);
            std::cerr << "Shader program linking failed: " << infoLog << std::endl;
            return -1;
        }
        checkGlError("glLinkProgram");

        GLfloat vertices[] = {
            0.0f,  0.5f, 0.0f,
           -0.5f, -0.5f, 0.0f,
            0.5f, -0.5f, 0.0f,
        };

        GLuint vbo;
        glGenBuffers(1, &vbo);
        checkGlError("glGenBuffers");
        glBindBuffer(GL_ARRAY_BUFFER, vbo);
        glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
        checkGlError("glBufferData");

        glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);
        checkGlError("glClear");

        glUseProgram(program);
        glEnableVertexAttribArray(0);
        glBindBuffer(GL_ARRAY_BUFFER, vbo);
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
        checkGlError("glVertexAttribPointer");



        printEglStreamState(eglDpy, eglStream, eglQueryStreamKHR);

        double time_tc = 0;
        const int count = 1;
        for(int i=0; i<count; i++){

            // 设置背景颜色为绿色(测试渲染)
            std::cout << "Started to render " << i << " frame." << std::endl;
            // glClearColor(0.0f, 1.0f, 0.0f, 1.0f); // 绿色背景
            // glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

            // Set viewport to match surface dimensions
            glViewport(0, 0, WIDTH, HEIGHT);

            // Clear frame buffer with non-black color to confirm rendering
            glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
            glClear(GL_COLOR_BUFFER_BIT);

            // Render triangle
            glUseProgram(program);
            glDrawArrays(GL_TRIANGLES, 0, 3);
            checkGlError("glDrawArrays");
            glFinish();
            checkGlError("glFinish");// Ensure rendering commands are executed

            std::vector<GLubyte> pixels(WIDTH * HEIGHT * 4);
            glReadPixels(0, 0, WIDTH, HEIGHT, GL_RGBA, GL_UNSIGNED_BYTE, pixels.data());
            checkGlError("glReadPixels");

            // 保存第一个帧缓冲内容到PPM文件
            std::ofstream ofs_1("output_1.ppm", std::ios::binary);
            ofs_1 << "P6\n" << WIDTH << " " << HEIGHT << "\n255\n";
            for (int y = HEIGHT - 1; y >= 0; --y) {
                for (int x = 0; x < WIDTH; ++x) {
                    int index = (y * WIDTH + x) * 4;
                    ofs_1.put(pixels[index]);     // R
                    ofs_1.put(pixels[index + 1]); // G
                    ofs_1.put(pixels[index + 2]); // B
                }
            }
            ofs_1.close();

            auto start = std::chrono::high_resolution_clock::now();

            // 推送渲染帧到 EGLStream 消费者(DisplayPort)
            if (!eglSwapBuffers(eglDpy, eglSurf)) {
                EGLint error = eglGetError();
                std::cerr << "eglSwapBuffers failed. EGL Error: 0x" << std::hex << error << std::endl;
            } else {
                std::cout << "Rendered frame pushed to EGLStream." << std::endl;




                printEglStreamState(eglDpy, eglStream, eglQueryStreamKHR);

                // while(true){
                //     // 消费者部分:尝试获取并处理帧
                //     std::cout << "Trying to acquire frame." << std::endl;

                //     printEglStreamState(eglDpy, eglStream, eglQueryStreamKHR);

                //     if (eglStreamConsumerAcquireKHR(eglDpy, eglStream)) {
                //         std::cout << "Consumer acquired a frame." << std::endl;

                //         // 这里可以添加消费者处理帧的逻辑,例如显示或编码
                //         // 目前仅模拟处理延迟
                //         std::this_thread::sleep_for(std::chrono::milliseconds(10));

                //         // 释放帧后
                //         if (!eglStreamConsumerReleaseKHR(eglDpy, eglStream)) {
                //             checkEglError("eglStreamConsumerReleaseKHR");
                //         } else {
                //             std::cout << "Consumer released the frame." << std::endl;
                //         }
                //         break;
                //     } else {
                //         EGLint error = eglGetError();
                //         if (error != EGL_BAD_STREAM_KHR && error != EGL_BAD_STATE_KHR) {
                //             std::cerr << "Failed to acquire frame. EGL Error: 0x" << std::hex << error << std::endl;
                //         }
                //     }
                //     std::this_thread::sleep_for(std::chrono::milliseconds(16)); // 大约16ms用于60fps
                // }
            }

            auto end = std::chrono::high_resolution_clock::now();
            std::chrono::duration<double, std::milli> elapsed = end - start;
            std::cout << "eglSwapBuffers execution time from VIDEO mem to CRTC Video mem: " << elapsed.count() << " ms" << std::endl;
            time_tc += elapsed.count();
            std::this_thread::sleep_for(std::chrono::milliseconds(16)); // 大约16ms


        }

        std::cout << "Average eglSwapBuffers execution time from VIDEO mem to CRTC Video mem: " << time_tc / double(count) << " ms" << std::endl;

        
        // Detect key press to exit
        while (true) {
            if(checkForKeyPress()){
                std::cout << "Key pressed, exiting..." << std::endl;
                break;
            }
            // Maintain 60fps
            std::this_thread::sleep_for(std::chrono::milliseconds(16)); // 大约16ms用于60fps
        }            
        

        // 检查渲染器信息
        const GLubyte* renderer = glGetString(GL_RENDERER);
        const GLubyte* version = glGetString(GL_VERSION);
        std::cout << "Renderer: " << renderer << std::endl;
        std::cout << "OpenGL version supported: " << version << std::endl;

        // 清理资源
        eglDestroySurface(eglDpy, eglSurf);
        eglDestroyStreamKHR(eglDpy, eglStream);
        eglDestroyContext(eglDpy, eglContext);
        eglTerminate(eglDpy);

        // 清理分配的 Output Layers 数组
        delete[] eglOutputLayers;

        return 0;
    } catch (const std::exception &ex) {
        std::cerr << "Error: " << ex.what() << std::endl;
        return EXIT_FAILURE;
    }
}

Thanks