SDL2在SDL_RenderClear()中卡住

SDL2 stucks in SDL_RenderClear()

本文关键字:RenderClear SDL SDL2      更新时间:2023-10-16

我有两个文件,一个是主文件(main.cpp),另一个是多线程文件(threads.cpp)。我使用SDL_PushEvent()在threads.cpp和SDL_PollEvent()在main.cpp。下面是我的示例代码的逻辑。

main.cpp

bool Init() {
    if (SDL_Init(SDL_INIT_VIDEO) < 0)
        return false;
    SDL_DisplayMode mode;
    SDL_GetDisplayMode(0, 0, &mode);
    this->win_width = mode.w;
    this->win_height = mode.h;
    this->win = SDL_CreateWindow(NULL, 0, 0, win_width, win_height, SDL_WINDOW_SHOWN | SDL_WINDOW_FULLSCREEN | SDL_WINDOW_OPENGL);
    if (this->win == NULL) {
        LOGE("[Init] SDL Window Created failed : %s", SDL_GetError());
        return false;
    }
    this->renderer = SDL_CreateRenderer(win, -1, SDL_RENDERER_ACCELERATED);
    if (this->renderer == NULL) {
        LOGE("[Init] SDL Renderer Created failed : %s", SDL_GetError());
        return false;
    }
    this->bmp = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGB565, SDL_TEXTUREACCESS_STREAMING, win_width, win_height);
    if (this->bmp == NULL) {
        LOGE("[Init] SDL Texture Created failed : %s", SDL_GetError());
        return false;
    }
    return true;
}
void DisplayEvent (SDL_Event e) {
    FrameObject obj = *(FrameObject*) e.user.data1;
    SDL_Rect rect;
    rect.x = rect.y = 0;
    rect.w = obj.frameWidth;
    rect.h = obj.frameHeight;
    int r = SDL_UpdateTexture(this->bmp, NULL, obj.FrameData.RGB, rect.w*2);
    LOGI("[DisplayEvent] - UpdateTexture");
    // Reneder this Frame
    SDL_RenderClear(this->renderer);
    LOGI("[DisplayEvent] - RenderClear");
    SDL_RenderCopy(this->renderer, this->bmp, NULL, &rect);
    LOGI("[DisplayEvent] - RenderCopy");
    SDL_RenderPresent(this->renderer);
    LOGI("[DisplayEvent] - RenderPresent");
}
int main (int argc, char **argv) {
    Init();
    while (!quit) {
        SDL_Event e;
        // Event Polling
        while (SDL_PollEvent(&e)) {
            switch (e.type) {
                case MY_EVENT:
                    LOGI("[main] - Get MY_EVENT");
                    DisplayEvent(e);
                    LOGI("[main] - %s more MY_EVENT", SDL_HasEvent(MY_EVENT) ? "Has" : "Hasn't");
                    break;
                default:
                    break;
            }
        }
    }
    SDL_Quit();
}

threads.cpp

void* push_event(void *arg) {
    FrameObject obj = (FrameObject*) arg;
    while (!quit) {
        SDL_Event event;
        SDL_zero(event);
        event.type = MY_EVENT;
        event.user.data1 = obj;
        event.user.data2 = 0;
        if (SDL_PushEvent(&event) == 1) LOGI("[push_event] - Push MY_EVENT");
        else LOGE("[push_event] - Event Push Error : %s", SDL_GetError());
        sleep(1);
    }
}

编辑:

我添加了更多的示例代码。我发现问题不是错过了SDL事件。问题是SDL线程(主线程)在SDL_RenderClear()被阻塞。

日志消息输出"[DisplayEvent] - UpdateTexture"但不打印"[DisplayEvent] - RenderClear"。这很奇怪。对于创建单个线程来运行push_event是找到的,但是当我创建两个线程来运行push_event时,SDL线程被阻塞了。

问题是硬件即GPU吗?

SDL Wiki上的SDL_PushEvent说它是线程安全的,所以我假设从其他线程调用它是可以的。但是,这里说您需要首先调用SDL_RegisterEvents以获得适合用作应用程序特定事件的事件ID,然后使用它来推送您的事件。

从你的代码中看不清楚,你是在调用SDL_RegisterEvents吗?这可能就是问题所在。另外,如果你在初始化视频的同一线程上推送事件,你是否检查过它是否有效?这个测试将确保问题与线程无关。