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

Wayland环境下SDL2程序无法显示窗口的问题求助

SDL2程序在Wayland环境下无法显示窗口的问题

问题描述

  • 切换至Wayland环境后,SDL2编写的C程序无法创建显示窗口
  • 程序已实现渲染器与事件循环,编译运行无报错
  • 修改SDL_VIDEODRIVER环境变量无效
  • 经调试确认事件循环已进入,且满足Wayland要求的事件循环与缓冲区提交条件
  • 系统环境:sway 1:1.8.1-5、Wayland 1.22.0-1、Linux 6.7.4.arch1-1

用户提供的代码:

#include <SDL2/SDL.h>
#include <stdbool.h>
#include <stdio.h>

const int SCREEN_HEIGHT = 1080;
const int SCREEN_WIDTH = 1920;

bool init(SDL_Window *window, SDL_Renderer *renderer);

void quit(SDL_Window *window, SDL_Renderer *renderer);

int main(int argc, char **argv) {
  SDL_Window *window = NULL;
  SDL_Renderer *renderer = NULL;

  if (!init(window, renderer)) {
    printf("init fail :( %s\n", SDL_GetError());
    quit(window, renderer);
    return 1;
  }
  bool quitGame = false;

  while (!quitGame) {

    SDL_RenderClear(renderer);
    SDL_Rect greenSquare = {SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2, 500, 500};
    SDL_RenderFillRect(renderer, &greenSquare);
    SDL_RenderPresent(renderer);

    SDL_Event e;
    while (SDL_PollEvent(&e)) {
      switch (e.type) {
      case SDL_QUIT:
        quitGame = true;
        break;
      case SDL_KEYDOWN:
        if (e.key.keysym.sym == SDLK_j) {
          printf("hi!");
        }
        break;
      }
    }

    SDL_Delay(100);
  }
  return 0;
}

bool init(SDL_Window *window, SDL_Renderer *renderer) {
  if (SDL_Init(SDL_INIT_VIDEO) < 0) {
    printf("sdl init fail :( %s\n", SDL_GetError());
    return false;
  }
  if (!SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "1")) {
    printf("warning: linear texture filtering not enabled :(");
  }

  window = SDL_CreateWindow("test window", SDL_WINDOWPOS_UNDEFINED,
                            SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH,
                            SCREEN_HEIGHT, SDL_WINDOW_SHOWN);
  if (window == NULL) {
    printf("window fail :( %s\n", SDL_GetError());
    return false;
  }

  renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
  if (renderer == NULL) {
    printf("renderer fail :( %s\n", SDL_GetError());
    return false;
  }

  SDL_SetRenderDrawColor(renderer, 0x00, 0xFF, 0x00, 0xFF);

  return true;
}

void quit(SDL_Window *window, SDL_Renderer *renderer) {
  SDL_DestroyRenderer(renderer);
  renderer = NULL;

  SDL_DestroyWindow(window);
  window = NULL;

  SDL_Quit();

  printf("bye \(;-\;)");
}

问题根源与修复方案

核心问题

init函数中,SDL_Window*和SDL_Renderer*采用值传递方式传入。函数内部对window和renderer的赋值仅作用于函数内的局部变量,不会修改main函数中声明的指针变量。这导致main里的window和renderer始终为NULL——虽然SDL对空指针操作有一定容错,程序不会直接崩溃,但实际窗口从未被创建成功。

修复方式一:使用指针的指针传递参数

修改init函数的参数类型为指针的指针,让函数能够修改main中的指针变量:

#include <SDL2/SDL.h>
#include <stdbool.h>
#include <stdio.h>

const int SCREEN_HEIGHT = 1080;
const int SCREEN_WIDTH = 1920;

bool init(SDL_Window **window, SDL_Renderer **renderer);

void quit(SDL_Window *window, SDL_Renderer *renderer);

int main(int argc, char **argv) {
  SDL_Window *window = NULL;
  SDL_Renderer *renderer = NULL;

  // 传入指针的地址
  if (!init(&window, &renderer)) {
    printf("init fail :( %s\n", SDL_GetError());
    quit(window, renderer);
    return 1;
  }
  bool quitGame = false;

  while (!quitGame) {
    SDL_RenderClear(renderer);
    SDL_Rect greenSquare = {SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2, 500, 500};
    SDL_RenderFillRect(renderer, &greenSquare);
    SDL_RenderPresent(renderer);

    SDL_Event e;
    while (SDL_PollEvent(&e)) {
      switch (e.type) {
      case SDL_QUIT:
        quitGame = true;
        break;
      case SDL_KEYDOWN:
        if (e.key.keysym.sym == SDLK_j) {
          printf("hi!");
        }
        break;
      }
    }

    SDL_Delay(100);
  }
  
  quit(window, renderer);
  return 0;
}

// 修改参数为指针的指针
bool init(SDL_Window **window, SDL_Renderer **renderer) {
  if (SDL_Init(SDL_INIT_VIDEO) < 0) {
    printf("sdl init fail :( %s\n", SDL_GetError());
    return false;
  }
  if (!SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "1")) {
    printf("warning: linear texture filtering not enabled :(");
  }

  // 通过指针的指针修改外部变量
  *window = SDL_CreateWindow("test window", SDL_WINDOWPOS_UNDEFINED,
                            SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH,
                            SCREEN_HEIGHT, SDL_WINDOW_SHOWN);
  if (*window == NULL) {
    printf("window fail :( %s\n", SDL_GetError());
    return false;
  }

  *renderer = SDL_CreateRenderer(*window, -1, SDL_RENDERER_ACCELERATED);
  if (*renderer == NULL) {
    printf("renderer fail :( %s\n", SDL_GetError());
    return false;
  }

  SDL_SetRenderDrawColor(*renderer, 0x00, 0xFF, 0x00, 0xFF);

  return true;
}

void quit(SDL_Window *window, SDL_Renderer *renderer) {
  if (renderer != NULL) {
    SDL_DestroyRenderer(renderer);
  }
  if (window != NULL) {
    SDL_DestroyWindow(window);
  }
  SDL_Quit();
  printf("bye \(;-\;)");
}

修复方式二:返回包含资源的结构体

定义一个结构体封装窗口和渲染器,让init函数返回该结构体,代码结构更清晰:

#include <SDL2/SDL.h>
#include <stdbool.h>
#include <stdio.h>

const int SCREEN_HEIGHT = 1080;
const int SCREEN_WIDTH = 1920;

typedef struct {
    SDL_Window* window;
    SDL_Renderer* renderer;
    bool initialized;
} AppContext;

AppContext init();
void quit(AppContext ctx);

int main(int argc, char **argv) {
  AppContext ctx = init();
  if (!ctx.initialized) {
    printf("init fail :( %s\n", SDL_GetError());
    quit(ctx);
    return 1;
  }
  bool quitGame = false;

  while (!quitGame) {
    SDL_RenderClear(ctx.renderer);
    SDL_Rect greenSquare = {SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2, 500, 500};
    SDL_RenderFillRect(ctx.renderer, &greenSquare);
    SDL_RenderPresent(ctx.renderer);

    SDL_Event e;
    while (SDL_PollEvent(&e)) {
      switch (e.type) {
      case SDL_QUIT:
        quitGame = true;
        break;
      case SDL_KEYDOWN:
        if (e.key.keysym.sym == SDLK_j) {
          printf("hi!");
        }
        break;
      }
    }

    SDL_Delay(100);
  }
  
  quit(ctx);
  return 0;
}

AppContext init() {
  AppContext ctx = {NULL, NULL, false};
  if (SDL_Init(SDL_INIT_VIDEO) < 0) {
    printf("sdl init fail :( %s\n", SDL_GetError());
    return ctx;
  }
  if (!SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "1")) {
    printf("warning: linear texture filtering not enabled :(");
  }

  ctx.window = SDL_CreateWindow("test window", SDL_WINDOWPOS_UNDEFINED,
                            SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH,
                            SCREEN_HEIGHT, SDL_WINDOW_SHOWN);
  if (ctx.window == NULL) {
    printf("window fail :( %s\n", SDL_GetError());
    return ctx;
  }

  ctx.renderer = SDL_CreateRenderer(ctx.window, -1, SDL_RENDERER_ACCELERATED);
  if (ctx.renderer == NULL) {
    printf("renderer fail :( %s\n", SDL_GetError());
    return ctx;
  }

  SDL_SetRenderDrawColor(ctx.renderer, 0x00, 0xFF, 0x00, 0xFF);
  ctx.initialized = true;
  return ctx;
}

void quit(AppContext ctx) {
  if (ctx.renderer != NULL) {
    SDL_DestroyRenderer(ctx.renderer);
  }
  if (ctx.window != NULL) {
    SDL_DestroyWindow(ctx.window);
  }
  SDL_Quit();
  printf("bye \(;-\;)");
}

额外优化

  • 在quit函数中增加空指针判断,避免对NULL资源执行销毁操作
  • main函数结束前主动调用quit函数,确保资源被正确释放

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 02:14:52