Running PySDL3 & OpenGL Applications on Ubuntu (WSL2) Запуск приложений PySDL3 и OpenGL на Ubuntu (WSL2)
This guide shows how to set up and run PySDL3 and PyOpenGL applications on Ubuntu inside Windows Subsystem for Linux (WSLg) without running into common graphics driver errors like Couldn't find matching GLX visual.
В этом руководстве показано, как настроить и запустить приложения PySDL3 и PyOpenGL на Ubuntu в Windows Subsystem for Linux (WSLg) без распространенных ошибок графического драйвера, таких как Couldn't find matching GLX visual.
1. Prerequisites 1. Предварительные требования
Install the required Python and graphics development packages in your Ubuntu terminal: Установите необходимые пакеты разработки Python и графики в терминале Ubuntu:
sudo apt update
sudo apt install -y python3-pip python3-venv libgl1-mesa-dev libegl1-mesa-dev
2. Set Up a Virtual Environment 2. Настройка виртуального окружения
Create and activate a Python virtual environment inside your project directory: Создайте и активируйте виртуальное окружение Python в директории вашего проекта:
mkdir -p ~/projects/pysdl3-app
cd ~/projects/pysdl3-app
python3 -m venv venv
source venv/bin/activate
3. Install Python Libraries 3. Установка библиотек Python
Install pysdl3, PyOpenGL, and numpy inside your active virtual environment:
Установите pysdl3, PyOpenGL и numpy в вашем активном виртуальном окружении:
pip install pysdl3 PyOpenGL numpy
4. Configure main.py Environment Overrides 4. Настройка переменных окружения в main.py
WSLg routes Linux graphics through Windows using Mesa. To prevent window initialization crashes, set platform environment variables before importing sdl3.
WSLg маршрутизирует графику Linux через Windows с помощью Mesa. Чтобы предотвратить сбои при инициализации окна, настройте переменные окружения платформы до импорта sdl3.
import ctypes
import os
import sys
import numpy as np
from OpenGL.GL import *
from OpenGL.GL.shaders import *
# Platform-specific environment setup (must be before importing sdl3)
if sys.platform.startswith("linux"):
os.environ["SDL_VIDEO_FORCE_EGL"] = "1"
os.environ["SDL_GL_DRIVER"] = "libEGL.so.1"
os.environ["SDL_VIDEODRIVER"] = "wayland,x11"
# Route rendering through software rasterization to bypass broken DRI3/WSL drivers
os.environ["GALLIUM_DRIVER"] = "llvmpipe"
os.environ["MESA_LOADER_DRIVER_OVERRIDE"] = "llvmpipe"
elif sys.platform.startswith("win32"):
os.environ["SDL_VIDEODRIVER"] = "windows"
os.environ["SDL_MAIN_USE_CALLBACKS"] = "1"
import sdl3
glContext = None
window = None
vertexShaderSource = """
attribute vec2 aPosition;
void main()
{
gl_Position = vec4(aPosition, 0.0, 1.0);
}
"""
fragmentShaderSource = """
void main()
{
gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
}
"""
@sdl3.SDL_AppInit_func
def SDL_AppInit(appstate, argc, argv):
global glContext
global window
if not sdl3.SDL_Init(sdl3.SDL_INIT_VIDEO):
sdl3.SDL_Log("Couldn't initialize SDL: %s".encode() % sdl3.SDL_GetError())
return sdl3.SDL_APP_FAILURE
sdl3.SDL_GL_SetAttribute(sdl3.SDL_GL_MULTISAMPLEBUFFERS, 1) # Enable MULTISAMPLE
sdl3.SDL_GL_SetAttribute(sdl3.SDL_GL_MULTISAMPLESAMPLES, 2) # Can be 2, 4, 8 or 16
windowTitle = "PySDL3, OpenGL".encode()
window = sdl3.SDL_CreateWindow(windowTitle, 350, 350, sdl3.SDL_WINDOW_OPENGL)
if not window:
sdl3.SDL_Log("Couldn't create a window: %s".encode() % sdl3.SDL_GetError())
return sdl3.SDL_APP_FAILURE
# Create an OpenGL context
glContext = sdl3.SDL_GL_CreateContext(window)
if not glContext:
sdl3.SDL_Log("Couldn't create a glContext: %s".encode() % sdl3.SDL_GetError())
return sdl3.SDL_APP_FAILURE
sdl3.SDL_GL_SetSwapInterval(1) # Turn on vertical sync
glClearColor(0.2, 0.2, 0.2, 1)
vertPositions = np.array([
-0.5, -0.5,
0.5, -0.5,
0, 0.5
], dtype=np.float32)
vertPosBuffer = glGenBuffers(1)
glBindBuffer(GL_ARRAY_BUFFER, vertPosBuffer)
glBufferData(GL_ARRAY_BUFFER, len(vertPositions) * 4,
vertPositions, GL_STATIC_DRAW)
program = compileProgram(
compileShader(vertexShaderSource, GL_VERTEX_SHADER),
compileShader(fragmentShaderSource, GL_FRAGMENT_SHADER))
glUseProgram(program)
aPositionLocation = glGetAttribLocation(program, "aPosition")
glVertexAttribPointer(aPositionLocation, 2, GL_FLOAT, GL_FALSE, 0, ctypes.c_void_p(0))
glEnableVertexAttribArray(aPositionLocation)
return sdl3.SDL_APP_CONTINUE
@sdl3.SDL_AppEvent_func
def SDL_AppEvent(appstate, event):
if sdl3.SDL_DEREFERENCE(event).type == sdl3.SDL_EVENT_QUIT:
return sdl3.SDL_APP_SUCCESS
return sdl3.SDL_APP_CONTINUE
@sdl3.SDL_AppIterate_func
def SDL_AppIterate(appstate):
glClear(GL_COLOR_BUFFER_BIT)
glDrawArrays(GL_TRIANGLES, 0, 3)
sdl3.SDL_GL_SwapWindow(window)
return sdl3.SDL_APP_CONTINUE
@sdl3.SDL_AppQuit_func
def SDL_AppQuit(appstate, result):
global glContext
sdl3.SDL_GL_DestroyContext(glContext)
# SDL will clean up the window/renderer for us
5. Run the Application 5. Запуск приложения
Execute your script with your virtual environment activated: Запустите скрипт с активированным виртуальным окружением:
python main.py
libEGL warning: DRI3 error in the terminal. The application automatically falls back to llvmpipe CPU software rendering and pops up the native window cleanly.
Примечание: Предупреждения libEGL warning: DRI3 error в терминале можно проигнорировать. Приложение автоматически переключается на программный рендеринг CPU llvmpipe и корректно отображает окно.
Support My Work Поддержать проект
If these tutorials helped you, consider buying me a coffee! Если эти туториалы вам помогли, вы можете поддержать автора.
Sberbank (Russia only) Сбербанк (только для РФ)
Direct transfer via phone number (Russia only) Перевод по номеру телефона (только для РФ)
USDT TRC20
Support via Cryptocurrency Поддержка криптовалютой