You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

树莓派3B上SDL2 KMSDRM启动无画面且鼠标异常的技术求助

问题描述

编写了一个利用SDL2的KMSDRM支持实现清屏为灰色的简单测试程序,代码如下:

#include <SDL.h>

#include <cstring>
#include <iostream>
#include <thread>

#include <SDL_opengles2.h>

using namespace std::chrono_literals;
using std::clog;
using std::endl;

int main()
{
    auto init_re = SDL_VideoInit("KMSDRM");
    if (init_re != 0)
        exit(EXIT_FAILURE);

    SDL_Window *window = SDL_CreateWindow("SDL2", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640, 480,
                                          SDL_WINDOW_SHOWN | SDL_WINDOW_OPENGL);
    if (nullptr == window)
    {
        std::cerr << "SDL_CreateWindow(): " << SDL_GetError() << '\n';
        exit(EXIT_FAILURE);
    }
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
    auto gl = SDL_GL_CreateContext(window);
    clog << "create OpenGL context " << gl << endl;
    auto make_current_re = SDL_GL_MakeCurrent(window, gl);
    clog << "make current ctx returned " << make_current_re << endl;
    clog << "OpenGL version: " << (const char *)glGetString(GL_VERSION) << ", GLSL "
         << (const char *)glGetString(GL_SHADING_LANGUAGE_VERSION) << endl;

    glClearColor(0.5, 0.5, 0.5, 1.0);
    size_t frame_count = 0;
    SDL_Event e;
    bool should_break = false;
    while (!should_break)
    {
        while (SDL_PollEvent(&e))
        {
            if (e.type == SDL_QUIT)
                should_break = true;
            else if (e.type == SDL_KEYDOWN)
                if (e.key.keysym.sym == SDLK_ESCAPE)
                    should_break = true;
        }

        frame_count += 1;
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
        clog << "frame " << frame_count << endl;
        std::this_thread::sleep_for(2ms);
    }

    SDL_GL_DeleteContext(gl);
    SDL_DestroyWindow(window);
    SDL_Quit();
}

程序可正常运行并打印帧计数日志,但无法显示640x480的灰色画面;此外,屏幕左上角显示鼠标指针但不随鼠标移动。

系统及配置信息:

  • 32位最新更新的Raspbian bullseye
  • 已完整卸载X服务器
  • 通过apt从Raspbian仓库安装SDL2
  • config.txt相关设置:
dtoverlay=vc4-kms-v3d,composite
max_framebuffers=2
gpu_mem=256

一、解决灰色画面无法显示的问题

核心问题是OpenGL ES双缓冲机制未被正确使用,同时窗口参数需要适配KMSDRM环境:

  1. 添加缓冲区交换调用
    OpenGL ES采用双缓冲,绘制内容默认在后台缓冲区,必须调用SDL_GL_SwapWindow才能将内容输出到屏幕。在glClear之后、休眠之前添加:
SDL_GL_SwapWindow(window);
  1. 调整窗口创建参数
    KMSDRM模式下,建议添加无框或全屏属性,同时指定窗口居中:
SDL_Window *window = SDL_CreateWindow("SDL2", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 640, 480,
                                      SDL_WINDOW_SHOWN | SDL_WINDOW_OPENGL | SDL_WINDOW_BORDERLESS);

若需适配屏幕原生分辨率,可替换为SDL_WINDOW_FULLSCREEN_DESKTOP。

  1. 提前设置OpenGL上下文属性
    将SDL_GL_SetAttribute移到窗口创建前,明确指定GLES版本:
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
// 之后再创建窗口
SDL_Window *window = SDL_CreateWindow(...);

二、解决KMSDRM模式下鼠标工作异常的问题

1. 修复鼠标指针不动的问题

  • 初始化输入子系统
    当前仅初始化了视频子系统,需补充初始化输入子系统以识别鼠标设备:
// 替换原SDL_VideoInit调用
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_INPUT) != 0) {
    std::cerr << "SDL_Init(): " << SDL_GetError() << '\n';
    exit(EXIT_FAILURE);
}
  • 处理光标显示(可选)
    若屏幕上是SDL默认软件光标,可禁用或切换为硬件光标:
// 禁用软件光标
SDL_ShowCursor(SDL_DISABLE);

Raspbian仓库的SDL2已默认支持libinput,硬件光标可通过SDL_CreateCursor自定义实现。

2. 确保输入设备权限

将当前用户加入input组,获取输入设备访问权限:

sudo usermod -aG input $USER

重启后生效。


内容的提问来源于stack exchange,提问作者jiandingzhe

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 13:20:37