Raspberry Pi 2 上的多线程 SDL2 渲染

SDL2 rendering with multithreading on Raspberry Pi 2

因此,我们正在尝试构建一个在进程内具有抢占功能的实时系统,将每个任务作为单独的线程执行。为了构建 GUI,选择了 SDL 库,我们将 GUI 初始化与渲染分开,以便后者可以成为不同的任务。尽管 SDL 本身有线程,但我们使用了 pthreads。发现的信息是矛盾的,因为一些消息来源指出渲染不能在不同的进程中执行,而其他消息来源则另有说明。然而,使用带有 Debian 的虚拟机,渲染被正确执行但是在 Raspberry Pi 中执行,通过改变主线程和渲染线程之间的上下文,SDL_GetError() 不会 return 错误但是不渲染任何导致带有光标的黑色 window。重要的是要说明主线程内的渲染在 Pi 和虚拟机中都按预期工作。

为了解决这个问题,在 Pi 和 SDL 配置中使用了几种替代方法。关于 Pi 本身,使用 sudo raspi-config,启用 OpenGL 的 Full 和 Fake KMS 都无法使用,并出现不同的错误:

完整 KMS - Could not initialize OpenGL / GLES library*

Fake KMS - * failed to add service - already in use?(键盘停止工作)。

OpenGL 禁用(原始)- 没有错误,黑色 window 未渲染。

以下,代码按线程显示:

主线程:

SDL_Window* GUI_init(int w, int h) {
  if (SDL_Init(SDL_INIT_VIDEO) != 0) {
    fprintf(stderr, "Cannot initialise SDL: %s\n", SDL_GetError());
    exit(1);
  }

  window = SDL_CreateWindow(
    "Tron", 
    SDL_WINDOWPOS_CENTERED, 
    SDL_WINDOWPOS_CENTERED, 
    w, h,
    SDL_WINDOW_SHOWN | SDL_WINDOW_OPENGL
  );
  if (window == NULL) {
    fprintf(stderr, "Unable to create window: %s\n", SDL_GetError());
    exit(1);
  }

  globalRenderer = SDL_CreateRenderer(
    window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC
  );
  if (globalRenderer == NULL) {
    fprintf(stderr, "Unable to create renderer: %s\n", SDL_GetError());
    exit(1);
  }

  if (SDL_SetRenderDrawBlendMode(globalRenderer, SDL_BLENDMODE_BLEND) != 0) {
    fprintf(stderr, "SDL_BlendMode failed: %s\n", SDL_GetError());
    exit(1);
  };

  ctx = SDL_GL_CreateContext(window);
  if(ctx == NULL) {
    fprintf(stderr, "Unable to create context: %s\n", SDL_GetError());
    exit(1);
  }

  int ctx1 = SDL_GL_MakeCurrent(window,NULL);
  if(ctx1!=0) {
    fprintf(stderr, "Unable to make currents context: %s\n", SDL_GetError());
    exit(1);
  }

  //return globalRenderer;
  return window;
}

渲染线程:

void* GUI_update(void* params) {
  SDL_GL_MakeCurrent(window,ctx);

  GUI_setRenderDrawColor(globalRenderer);

  SDL_RenderClear(globalRenderer);

  GUI_fillBoardBorders(globalRenderer);
  GUI_fillBoard(globalRenderer);

  SDL_RenderPresent(globalRenderer);
}

使用 3 个全局变量:

SDL_Window *window = NULL;
SDL_GLContext ctx = NULL;
SDL_Renderer* globalRenderer = NULL;

我们使用 Raspbian Jessie Lite 作为 OS。这可能是什么问题?

SDL_Renderer top-level documentation:

This API is not designed to be used from multiple threads, see SDL bug #1995 for details.

更多authoritatively:

/**
 *  \file SDL_render.h
 *
 *  Header file for SDL 2D rendering functions.
 *
 *  This API supports the following features:
 *      * single pixel points
 *      * single pixel lines
 *      * filled rectangles
 *      * texture images
 *
 *  The primitives may be drawn in opaque, blended, or additive modes.
 *
 *  The texture images may be drawn in opaque, blended, or additive modes.
 *  They can have an additional color tint or alpha modulation applied to
 *  them, and may also be stretched with linear interpolation.
 *
 *  This API is designed to accelerate simple 2D operations. You may
 *  want more functionality such as polygons and particle effects and
 *  in that case you should use SDL's OpenGL/Direct3D support or one
 *  of the many good 3D engines.
 *
 *  These functions must be called from the main thread.
 *  See this bug for details: http://bugzilla.libsdl.org/show_bug.cgi?id=1995
 */

此外,请勿尝试同时使用 OpenGL 和 SDL_RENDERER_ACCELERATED SDL_Renderer。 SDL_Renderer 不提供任何方式 save/restore 它可能正在使用的 OpenGL 状态。