프로그래밍/Python

Docker에 OpenGL 환경 설정하기까지의 과정

유태정 2022. 3. 18. 23:08
반응형

작업환경은 Intel Iris Plus Graphics를 탑재한 MacBook Pro 2020년형이다.

Visual Studio Code에서 작업할 것이며, Docker에 Ubuntu20.04 이미지를 사용할 것이다.

내 목표는 이 환경에서 파이썬 3.7 버전으로 OpenGL 창을 띄우는 것이다.

아래는 이를 위한 삽질을 기록하도록 한다. 

도커 환경 설정

https://docs.microsoft.com/ko-kr/learn/modules/use-docker-container-dev-env-vs-code/

 

Visual Studio Code에서 Docker 컨테이너를 개발 환경으로 사용 - Learn

Visual Studio Code Remote - Containers 확장을 사용하여 완전한 기능을 갖춘 컨테이너 기반 개발 환경을 만들고 구성합니다. 컨테이너에서 폴더 또는 리포지토리를 열고 IntelliSense(완성), 코드 탐색, 디버

docs.microsoft.com

마이크로소프트 개발자 가이드에 친절히 나와있으므로, 이를 참고하도록 하자

파이썬 3.7 설치하기

기본적으로 파이썬 3.8 버전이 설치돼 있다. 나는 파이썬 3.7 버전이 필요한데 이를 설치하려면 다음의 방법을 참고하자.

https://askubuntu.com/questions/682869/how-do-i-install-a-different-python-version-using-apt-get

 

How do I install a different Python version using apt-get?

How can I install a different version of Python using apt-get? Obviously I realise I can install using the source tar ball, however I would prefer not to install from source and instead use the pa...

askubuntu.com

위를 따라하려고 하더라도 add-apt-repository라는 명령어를 찾을 수 없다며 첫 줄부터 막힌다. 이 때는 apt-get update를 한 번 실행해준 이후 다음을 따라하자.

https://nancom.tistory.com/119

 

[Solution] sudo: add-apt-repository: command not found

$sudo add-apt-repository XXXX를 입력했을시에 sudo: add-apt-repository: command not found 라고 뜨면서 진행이 되지 않는 경우가 발생한다. 방법은 두가지가 있다. Solution 1. python-software-properties..

nancom.tistory.com

위에서 소개한 내용 중 두 번째 해결책을 시도하자.

파이썬 기본 버전 설정하기

파이썬 3.7을 설치했다고 하더라도 python을 터미널에 입력해도 명령어를 찾을 수 없다고 뜬다.

시스템 환경변수 PATH에도 파이썬이 설치된 경로는 추가돼 있지 않다.

사실, python3를 입력하면 파이썬을 실행할 수 있지만 기본 버전이 3.8이다.

다음 명령어를 입력하여 파이썬 기본 버전을 설정할 수 있다.

sudo update-alternative /usr/bin/python python /usr/bin/python3.7 1

출처가 어디었는지는 기억나지 않는다.

아무튼, 이제 터미널에 python을 입력하면 3.7 버전이 기본적으로 실행된다.

PIP 설치하기

어째서인지 없다. 다음 글을 참고하여 설치하자

https://devlog.jwgo.kr/2020/02/29/broken-pip-error/

 

No module named 'pip' 에러와 함께 pip가 갑자기 안되는 경우 · Tonic

사이트 운영에 도움을 주실 수 있습니다. 고맙습니다. --> No module named 'pip' 에러와 함께 pip가 갑자기 안되는 경우 2020년 02월 29일 문제 몇 분 전까지만 해도 잘 되던 pip가 갑자기 No module named 'pip'메

devlog.jwgo.kr

필요한 모듈 설치하기

glfw, pyopengl, numpy가 필요하다. pip으로 설치하고 pip show <package>를 통해 3.7 버전에 잘 설치됐는지 검토하자.

GLFW 테스트

이제 파이썬을 실행하여 glfw를 import하고 glfw.init()을 입력하면 다음과 같은 오류가 뜰거다.

/home/vscode/.local/lib/python3.7/site-packages/glfw/__init__.py:906: GLFWError: (65544) b'X11: The DISPLAY environment variable is missing' warnings.warn(message, GLFWError) 0

말그대로 DISPLAY 환경변수가 설정되지 않아서 뜨는 문제다. 다음 링크를 참고하여 따라하자.

https://hanseokhyeon.tistory.com/entry/Mac-Docker-에서-GUI-사용하기-python-matplotlib-사용하기

 

Mac + Docker 에서 GUI 사용하기 (python matplotlib 사용하기)

모든 개발 환경을 Docker로 넘어가고 있는 시점에서 계속 난관에 봉착한다. 이번 난관은 바로 Mac + Docker + matplotlib다. 우선 Docker는 리눅스 서버이기 때문에 GUI가 없다. 말이 조금 이상한데 리눅스에

hanseokhyeon.tistory.com

socat 명령어를 입력했는데 다음과 같은 오류가 떴다면 XQuartz가 켜져 있어서 그렇다. 끄자.

다른 서버가 우연히 같은 포트를 쓸 수 있지만 그건 알아서 하자.

socat[2209] E bind(5, {LEN=0 AF=2 0.0.0.0:6000}, 16): Address already in use

DISPLAY 환경변수 설정

DISPLAY 환경변수의 값은 자신의 아이피(도커 밖에서 ifconfig en0로 확인되는 아이피)에 :0을 붙인 값이다.

나의 경우 (지금 네트워크 환경에서는) 192.168.0.9:0이 그 값이 되겠다. 다음을 참고하여 설정하자. 두 번째까지 진행하자.

https://mkyong.com/linux/how-to-set-environment-variable-in-ubuntu/

필수 라이브러리 설치

위에까지 마친 이후 glfw.init()을 실행해보면 또 다른 문제가 생길 것이다. 라이브러리가 없어서 생기는 문제일 것이므로 libglfw, libglfw-dev 라이브러리를 설치해줌으로써 해결할 수 있다.

그래픽 드라이버 설치

이제 될 법도 한데, 심지어 XQuartz 테스트 프로그램도 잘 돌아가지만 OpenGL 창을 띄우려 하면 다음 오류가 뜨며 안 된다.

libGL error: No matching fbConfigs or visuals found libGL error: failed to load driver: swrast /home/vscode/.local/lib/python3.7/site-packages/glfw/__init__.py:906: GLFWError: (65543) b'GLX: Failed to create context: BadValue (integer parameter out of range for operation)' warnings.warn(message, GLFWError)

glfw.create_window 함수에서 문제가 생긴다. 인텔 내장 그래픽이므로 libgl1-mesa-glx, libgl1-mesa-dri 패키지를 설치하였으나 문제가 해결되지 않는다. 추가적으로 환경변수 LIBGL_ALWAYS_INDIRECT를 1로 설정하고 libgl1-utils, libgl1-mesa-glx 패키지도 설치했다.

https://unix.stackexchange.com/questions/589236/libgl-error-no-matching-fbconfigs-or-visuals-found-glxgears-error-docker-cu

 

libGL error: No matching fbConfigs or visuals found | Glxgears error, Docker, CUDA, VirtualGL

when I run glxgears, I get following error. libGL error: No matching fbConfigs or visuals found libGL error: failed to load driver: swrast Error: couldn't get an RGB, Double-buffered visual My sy...

unix.stackexchange.com

X Quartz 키워드를 포함하여 검색해보니 해결책을 찾았다. 도커 외부에서 터미널을 열고 X Quartz의 설정을 바꿔줘야 한다. 아래 링크에서 제안한대로 치면 되는데 중간에 org로 시작하는 값을 다음으로 대체하면 된다.

defaults write org.xquartz.X11 enable_iglx -bool true

https://services.dartmouth.edu/TDClient/1806/Portal/KB/ArticleDet?ID=89669 

 

Installing XQuartz and Enabling GLX (OpenGL).

Install XQuartz and enable display of OpenGL from remote systems.

services.dartmouth.edu

이렇게 했더니 윈도우가 뜨긴 하지만, 비어있다.

GUI 프로그램 실행 테스트

다음 링크에서 소개된 GUI 프로그램들을 설치하여 실행해보았는데, 모두 잘 실행된다.

https://docs.microsoft.com/ko-kr/windows/wsl/tutorials/gui-apps

 

WSL을 사용하여 Linux GUI 앱 실행

WSL에서 Linux GUI 앱 실행을 지원하는 방법을 알아봅니다.

docs.microsoft.com

VLC에서 OpenGL로 비디오 출력 설정을 바꿔도 잘 재생된다. (연관이 얼마나 있는지는 모르겠지만)

다만, OpenGL로 개발하여 컴파일 하여 실행했을 때는 모두 내용이 그려지지 않는다.

OpenGL 샘플 코드 실행

OpenGL 홈페이지에서 샘플 코드를 다운로드 받아 실행할 수 있다.

하지만 GLFW가 아닌 GLUT를 사용하는 옛 코드다.

GLUT를 설치하여 실행했는데 잘 실행된다.

이로써 GLFW의 문제임이 유력해졌다.

보류

주말 동안, 그리고 앞으로 할 일이 많아서 이 문제는 보류해야겠다.

1. ccmake를 통해 cmake 옵션을 추가하여 빌드했다. 테스트 프로젝트들도 빌드 되는데 이것저것 실행하다보면 잘 실행되는 것도 있고 아닌 것도 있다. 그 오류를 분석하면 문제를 해결할 실마리가 보일 듯 싶다.

https://www.glfw.org/docs/latest/compile.html

 

GLFW: Compiling GLFW

This is about compiling the GLFW library itself. For information on how to build applications that use GLFW, see Building applications. Using CMake NoteGLFW behaves like most other libraries that use CMake so this guide mostly describes the basic configure

www.glfw.org

2. OpenGL 설치와 관련된 설명은 아래 링크에 자세히 나와있다. 미래에 다시 이 문제를 해결할 때 참고하도록 하자.

https://medium.com/geekculture/a-beginners-guide-to-setup-opengl-in-linux-debian-2bfe02ccd1e 

 

A Beginner’s Guide to Setup OpenGL in Linux (Debian)

Step-by-step guide for setting up OpenGL in Ubuntu along with the installation of required libraries: GLFW and GLAD.

medium.com

3. 지금 직면한 문제는 크게 세 가지다.

import glfw
from OpenGL.GL import *
import OpenGL.GL.shaders
import numpy
 
 
def main():
 
    # initialize glfw
    if not glfw.init():
        return
 
    window = glfw.create_window(800, 600, "My OpenGL window", None, None)
 
    if not window:
        glfw.terminate()
        return
 
    glfw.make_context_current(window)
    #            positions        colors
    triangle = [-0.5, -0.5, 0.0, 1.0, 0.0, 0.0,
                 0.5, -0.5, 0.0, 0.0, 1.0, 0.0,
                 0.0,  0.5, 0.0, 0.0, 0.0, 1.0]
 
    triangle = numpy.array(triangle, dtype = numpy.float32)
 
    vertex_shader = """
    #version 330
    in vec3 position;
    in vec3 color;
    out vec3 newColor;
    void main()
    {
        gl_Position = vec4(position, 1.0f);
        newColor = color;
    }
    """
 
    fragment_shader = """
    #version 330
    in vec3 newColor;
    out vec4 outColor;
    void main()
    {
        outColor = vec4(newColor, 1.0f);
    }
    """
    vao = glGenVertexArrays(1)
    glBindVertexArray(vao)

    shader = OpenGL.GL.shaders.compileProgram(OpenGL.GL.shaders.compileShader(vertex_shader, GL_VERTEX_SHADER),
                                              OpenGL.GL.shaders.compileShader(fragment_shader, GL_FRAGMENT_SHADER))
 
    VBO = glGenBuffers(1)
    glBindBuffer(GL_ARRAY_BUFFER, VBO)
    glBufferData(GL_ARRAY_BUFFER, 72, triangle, GL_STATIC_DRAW)
 
    position = glGetAttribLocation(shader, "position")
    glVertexAttribPointer(position, 3, GL_FLOAT, GL_FALSE, 24, ctypes.c_void_p(0))
    glEnableVertexAttribArray(position)
 
    color = glGetAttribLocation(shader, "color")
    glVertexAttribPointer(color, 3, GL_FLOAT, GL_FALSE, 24, ctypes.c_void_p(12))
    glEnableVertexAttribArray(color)
 
 
    glUseProgram(shader)
 
    glClearColor(0.2, 0.3, 0.2, 1.0)
 
    while not glfw.window_should_close(window):
        glfw.poll_events()
 
        glClear(GL_COLOR_BUFFER_BIT)
 
        glDrawArrays(GL_TRIANGLES, 0, 3)
 
        glfw.swap_buffers(window)
 
    glfw.terminate()
 
if __name__ == "__main__":
    main()

위 코드에서 발생하는 오류는 아래와 같다. (파이썬)

Traceback (most recent call last): File "test.py", line 83, in <module> main() File "test.py", line 52, in main OpenGL.GL.shaders.compileShader(fragment_shader, GL_FRAGMENT_SHADER)) File "/usr/local/lib/python3.7/dist-packages/OpenGL/GL/shaders.py", line 211, in compileProgram program.check_validate() File "/usr/local/lib/python3.7/dist-packages/OpenGL/GL/shaders.py", line 112, in check_validate glGetProgramInfoLog( self ), OpenGL.GL.shaders.ShaderValidationError: Validation failure (0):
#include <GLFW/glfw3.h>
#include <stdlib.h>
#include <stdio.h>
#include <iostream>

using namespace std;

static void error_callback(int error, const char* description)
{
    fputs(description, stderr);
}
static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
{
    if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
        glfwSetWindowShouldClose(window, GL_TRUE);
}
int main(void)
{
    GLFWwindow* window;
    glfwSetErrorCallback(error_callback);
    if (!glfwInit())
        exit(EXIT_FAILURE);

    // cout << "default shader lang: " << glGetString(GL_SHADING_LANGUAGE_VERSION) << endl;

    // select opengl version
    // int major, minor, rev;
    // glfwGetVersion(&major, &minor, &rev);
    // cout << "glfw major.minor " << major << "." << minor << "." << rev << endl;
    
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
    //glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);


    window = glfwCreateWindow(640, 480, "Simple example", NULL, NULL);
    if (!window)
    {
        glfwTerminate();
        exit(EXIT_FAILURE);
    }
    glfwMakeContextCurrent(window);

    cout << "OpenGL shader language version: " << glGetString(GL_SHADING_LANGUAGE_VERSION) << endl;


    glfwSetKeyCallback(window, key_callback);
    while (!glfwWindowShouldClose(window))
    {
        float ratio;
        int width, height;
        glfwGetFramebufferSize(window, &width, &height);
        ratio = width / (float) height;
        glViewport(0, 0, width, height);
        glClear(GL_COLOR_BUFFER_BIT);
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        glOrtho(-ratio, ratio, -1.f, 1.f, 1.f, -1.f);
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
        glRotatef((float) glfwGetTime() * 50.f, 0.f, 0.f, 1.f);
        glBegin(GL_TRIANGLES);
        glColor3f(1.f, 0.f, 0.f);
        glVertex3f(-0.6f, -0.4f, 0.f);
        glColor3f(0.f, 1.f, 0.f);
        glVertex3f(0.6f, -0.4f, 0.f);
        glColor3f(0.f, 0.f, 1.f);
        glVertex3f(0.f, 0.6f, 0.f);
        glEnd();
        glfwSwapBuffers(window);
        glfwPollEvents();
    }
    glfwDestroyWindow(window);
    glfwTerminate();
    exit(EXIT_SUCCESS);
}

위에서 발생하는 오류는 아래와 같다. (C++)

컴파일 옵션: g++ test.cc -o test -lGL -lGLU -lglfw -lX11 -lXxf86vm -lXrandr -lpthread -lXi

GLX: Forward compatibility requested but GLX_ARB_create_context_profile is unavailable

그리고 마지막 문제는 창에 아무것도 출력되지 않는 문제.

반응형