pax_global_header00006660000000000000000000000064145124473360014523gustar00rootroot0000000000000052 comment=1573e57e5423b313599155c7e4bc9c5253065f40 moderngl-glcontext-1573e57/000077500000000000000000000000001451244733600156215ustar00rootroot00000000000000moderngl-glcontext-1573e57/.github/000077500000000000000000000000001451244733600171615ustar00rootroot00000000000000moderngl-glcontext-1573e57/.github/icon.svg000066400000000000000000000100121451244733600206240ustar00rootroot00000000000000 moderngl-glcontext-1573e57/.github/workflows/000077500000000000000000000000001451244733600212165ustar00rootroot00000000000000moderngl-glcontext-1573e57/.github/workflows/build.yml000066400000000000000000000026031451244733600230410ustar00rootroot00000000000000name: build on: push: branches: [master] pull_request: branches: [master] workflow_dispatch: jobs: build: name: build runs-on: ${{ matrix.os }} strategy: matrix: os: [ubuntu-latest, windows-latest] python-version: ['3.7', '3.8', '3.9', '3.10', '3.11'] architecture: ['x64'] steps: - uses: actions/checkout@v3 - name: setup uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} architecture: ${{ matrix.architecture }} - name: deps run: python -m pip install -U pip wheel setuptools - name: wheel run: python setup.py bdist_wheel build-aarch64: strategy: fail-fast: false runs-on: ubuntu-latest env: py: /opt/python/cp39-cp39/bin/python img: quay.io/pypa/manylinux2014_aarch64 steps: - name: Checkout uses: actions/checkout@v3 - name: Set up QEMU id: qemu uses: docker/setup-qemu-action@v1 - name: Install dependencies run: | docker run --rm -v ${{ github.workspace }}:/ws:rw --workdir=/ws \ ${{ env.img }} \ bash -exc '${{ env.py }} -m venv .env && \ source .env/bin/activate && \ python -m pip install -U pip wheel setuptools && \ python setup.py bdist_wheel && \ deactivate' moderngl-glcontext-1573e57/.github/workflows/publish.yml000066400000000000000000000043561451244733600234170ustar00rootroot00000000000000name: Publish on: # push: release: types: [created] workflow_dispatch: jobs: build_wheels: name: Build Wheels on ${{ matrix.os }}-${{ matrix.cibw_archs }} runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: os: [ubuntu-18.04, windows-2019, macos-10.15] cibw_archs: ["auto64"] include: - os: ubuntu-18.04 cibw_archs: "aarch64" - os: ubuntu-18.04 cibw_archs: "auto32" - os: windows-2019 cibw_archs: "auto32" steps: - uses: actions/checkout@v3 - name: Set up QEMU if: matrix.cibw_archs == 'aarch64' uses: docker/setup-qemu-action@v1 with: platforms: arm64 - name: Build wheels uses: pypa/cibuildwheel@v2.16.2 with: output-dir: dist/ env: CIBW_ARCHS_MACOS: "x86_64 universal2" CIBW_BUILD: cp38-* cp39-* cp310-* cp311-* cp312-* pp* CIBW_ARCHS: ${{ matrix.cibw_archs }} CIBW_SKIP: "*-musllinux*" - uses: actions/upload-artifact@v2 with: path: ./dist/*.whl name: wheels-${{ runner.os }}-${{ matrix.cibw_archs }} # Build the source distribution under Linux build_sdist: name: Source distribution runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Build source distribution run: pipx run build --sdist - name: Store artifacts uses: actions/upload-artifact@v2 with: path: dist/*.tar.gz publish: name: publish needs: - build_sdist - build_wheels runs-on: ubuntu-latest # if: ${{ github.event_name == 'release' && github.event.action == 'created' }} steps: - name: download uses: actions/download-artifact@v2 with: path: temp-dist/ # Only copy the wheels and source dist files. Additional lingering # files will cause issues - name: Copy Files to dist shell: bash run: | mkdir dist cp temp-dist/*/*.whl dist/ cp temp-dist/*/*.tar.gz dist/ - uses: pypa/gh-action-pypi-publish@v1.4.2 with: user: __token__ password: ${{ secrets.PYPI_API_TOKEN }} moderngl-glcontext-1573e57/.github/workflows/release.yml000066400000000000000000000015321451244733600233620ustar00rootroot00000000000000name: release on: workflow_dispatch: jobs: release: name: Build wheels on ${{ matrix.os }} runs-on: ${{ matrix.os }} strategy: matrix: os: [ubuntu-20.04, windows-2019, macos-11] steps: - uses: actions/checkout@v3 - name: setup uses: actions/setup-python@v4 with: python-version: '3.11' architecture: x64 - name: update run: python -m pip install -U pip wheel setuptools - name: deps run: python -m pip install cibuildwheel==2.16.2 - name: sdist if: matrix.os == 'ubuntu-20.04' run: python setup.py sdist -d package - name: wheels run: python -m cibuildwheel --output-dir package - name: upload uses: actions/upload-artifact@v3 with: name: package path: package moderngl-glcontext-1573e57/.gitignore000066400000000000000000000001661451244733600176140ustar00rootroot00000000000000/.vscode/* /.pytest_cache /.cache /build /dist __pycache__ *.egg-info *.pyc *.pyd *.pbd *.lib *.so temp_* .venv moderngl-glcontext-1573e57/CHANGELOG.md000066400000000000000000000031651451244733600174370ustar00rootroot00000000000000 # Change Log ## 2.3.7 Python 3.11 support ## 2.3.6 Expose headless/standalone flag ## 2.3.3 * Missing manylinux wheels for python 3.9 * Minor issue in setup.py ## 2.3.0 python 3.9 support ## 2.3.dev0 * EGL backend will now use `eglQueryDevicesEXT` instead of only relying on `EGL_DEFAULT_DISPLAY` * EGL backend now supports `device_index` for selecting a device ## 2.2.0 * x11 and egl backend will now use `ctypes.utils.find_library` to locate GL and EGL if not `libgl` and `libegl` parameter is passed to the backend ## 2.1.0 * Support setting backend arguments using environment variables. * `GLCONTEXT_GLVERSION` for setting opengl version * `GLCONTEXT_LINUX_LIBGL` for specifying libgl name * `GLCONTEXT_LINUX_LIBX11` for specifying libx11 name * `GLCONTEXT_LINUX_LIBEGL` for specifying libegl name * `GLCONTEXT_WIN_LIBGL` for specifying dll name * x11: More details in error messages ## 2.0.0 Support passing in values to backends for more detailed configuration. Method signatures have changed so upgrading from 1.* needs smaller code changes. - `default_backend()` no longer takes any arguments - The returned backend now takes `glversion` and other arguments - The `standalone` argument is now called `mode` and can contain `standalone`, `share` and `detect`. - Added `get_backend` for requesting specific backends like EGL. ## 1.0.1 * darwin: Fixed a segfault when releasing a context * x11: Fixed an issue causing context creation to fail ## 1.0.0 Initial release. Contains backends for wgl, darwin and x11 including experimental egl backend. moderngl-glcontext-1573e57/LICENSE000066400000000000000000000020661451244733600166320ustar00rootroot00000000000000MIT License Copyright (c) 2021 ModernGL Contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. moderngl-glcontext-1573e57/MANIFEST.in000066400000000000000000000001121451244733600173510ustar00rootroot00000000000000recursive-include glcontext *.cpp *.hpp include README.md include LICENSE moderngl-glcontext-1573e57/README.md000066400000000000000000000124061451244733600171030ustar00rootroot00000000000000[![pypi](https://badge.fury.io/py/glcontext.svg)](https://pypi.python.org/pypi/glcontext) # glcontext **glcontext** is a library providing OpenGL implementation for ModernGL on multiple platforms. * [glcontext on github](https://github.com/moderngl/glcontext) * [glcontext on pypi](https://pypi.org/project/glcontext) * [ModernGL](https://github.com/moderngl/moderngl) ## Backends A glcontext backend is either an extension or a submodule of the glcontext package. The package itself does not import any of the backends. Importing the base package `glcontext` must safe and lightweight. ## Structure Every backend of glcontext must provide a factory function: ```py def create_context(*args, **kwargs) -> GLContext: pass ``` The create\_context method can take any number of positional and keyword arguments. The factory function must return an object supporting the following methods: ```py def load(self, name:str) -> int: pass ``` The load method takes an OpenGL function name as an input and returns a C/C++ function pointer as a python integer. The return value must be 0 for not implemented functions. ```py def __enter__(self, name:str): pass ``` The enter method calls `___MakeCurrent` to make the GLContext the calling thread's current rendering context. `___MakeCurrent` stands for `wglMakeCurrent`, `glxMakeCurrent`, ... ```py def __exit__(self, exc_type, exc_val, exc_tb): pass ``` The exit method calls `___MakeCurrent` to make the GLContext no longer current. ```py def release(self): pass ``` The release method destroys the OpenGL context. ## Development Guide There are "empty" example backends provided for developers to help adding new backends to the library. There is a pure python example in [empty.py](#) and an extension example in [empty.cpp](#). Besides their name match, they do not depend on each other, they are independent submodules of glcontext. An "portable" backend implementation must load its dependency at runtime. This rule is for simplifying the build of the entire package. If an implementation cannot provide a "portable" backend, it will not be added to this library. Non "portable" backends are welcome as third party libraries. A backend must be lightweight, its size must fit within reasonable limits. To add support for new platforms one must edit the `setup.py` too. Platform specific dependencies are exceptions from the "portability" rule. Example for platform specific dependencies: - `gdi32.lib` on windows - `libdl.a` on linux Please note that `libGL.so` is loaded dinamically by the backends. ## Current backends Each backend supports a `glversion` and `mode` parameters as a minimum. The `glversion` is the minimum OpenGL version required while `mode` decides how the context is created. Modes * `detect`: Will detect an existing active OpenGL context. * `standalone`: Crates a headless OpenGL context * `share`: Creates a new context sharing objects with the currently active context (headless) ### wgl Parameters * `glversion` (`int`): The minimum OpenGL version for the context * `mode` (`str`): Creation mode. `detect` | `standalone` | `share` * `libgl` (`str`): Name of gl library to load (default: `opengl32.dll`) ### x11 If `libgl` is not passed in the backend will try to locate the GL library using `ctypes.utils.find_library`. Parameters * `glversion` (`int`): The minimum OpenGL version for the context * `mode` (`str`): Creation mode. `detect` | `standalone` | `share` * `libgl` (`str`): Name of gl library to load (default: `libGL.so`) * `libx11` (`str`): Name of x11 library to load (default: `libX11.so`) ### darwin Will create the the highest core context available. Parameters * `mode` (`str`): Creation mode. `detect` | `standalone` ### egl Only supports standalone mode. If `libgl` and/or `libegl` is not passed in the backend will try to locate GL and/or EGL library using `ctypes.utils.find_library`. Parameters * `glversion` (`int`): The minimum OpenGL version for the context * `mode` (`str`): Creation mode. `standalone` * `libgl` (`str`): Name of gl library to load (default: `libGL.so`) * `libegl` (`str`): Name of gl library to load (default: `libEGL.so`) * `device_index` (`int`) The device index to use (default: `0`) ## Environment Variables Environment variables can be set to configure backends. These will get first priority if defined. ```bash # Override OpenGL version code. For example: 410 (for opengl 4.1) GLCONTEXT_GLVERSION # Override libgl on linux. For example: libGL.1.so GLCONTEXT_LINUX_LIBGL # Override libx11 on linux. For exampleØ libX11.x.so GLCONTEXT_LINUX_LIBX11 # Override libegl on linux. For exampleØ libEGL.x.so GLCONTEXT_LINUX_LIBEGL # Override gl dll on windows. For example: opengl32_custom.dll GLCONTEXT_WIN_LIBGL # Override the device index (egl) GLCONTEXT_DEVICE_INDEX ``` ## Running tests ``` pip install -r tests/requirements.txt pytest tests ``` ## Contributing Contribution is welcome. Pull Requests will be merged if they match the [Development Guide](#). For prototypes, pure python implementations using ctypes are also welcome. We will probably port it to a proper extension in the future. Please ask questions [here](https://github.com/moderngl/glcontext/issues). moderngl-glcontext-1573e57/glcontext/000077500000000000000000000000001451244733600176305ustar00rootroot00000000000000moderngl-glcontext-1573e57/glcontext/__init__.py000066400000000000000000000102011451244733600217330ustar00rootroot00000000000000import os __version__ = '2.3.7' def default_backend(): """Get default backend based on the detected platform. Supports detecting an existing context and standalone contexts. If no context if found for the platform we return the linux backend. Example:: # Get the available backend backend = get_default_backend(standalone=False/True) # Create an opengl 3.3 context or detect the currently active # context requiring at least opengl 3.3 support. ctx = backend(330) Returns: A backend object for creating and/or detecting context """ PLATFORMS = {'windows', 'linux', 'darwin'} import platform target = platform.system().lower() for known in PLATFORMS: if target.startswith(known): target = known if target not in PLATFORMS: target = 'linux' if target == 'windows': return _wgl() if target == 'linux': return _x11() if target == 'darwin': return _darwin() raise ValueError("Cannot find suitable default backend") def get_backend_by_name(name: str): """Request a specific backend by name""" if name == 'egl': return _egl() raise ValueError("Cannot find supported backend: '{}'".format(name)) def _wgl(): """Create wgl backend""" from glcontext import wgl def create(*args, **kwargs): _apply_env_var(kwargs, 'glversion', 'GLCONTEXT_GLVERSION', arg_type=int) _apply_env_var(kwargs, 'libgl', 'GLCONTEXT_WIN_LIBGL') # make sure libgl is an absolute path if 'libgl' in kwargs: _libgl = kwargs['libgl'] if '/' in _libgl or '\\' in _libgl: kwargs['libgl'] = os.path.abspath(_libgl) kwargs = _strip_kwargs(kwargs, ['glversion', 'mode', 'libgl']) return wgl.create_context(**kwargs) return create def _x11(): """Create x11 backend""" from glcontext import x11 from ctypes.util import find_library def create(*args, **kwargs): if not kwargs.get('libgl'): kwargs['libgl'] = find_library('GL') if not kwargs.get('libx11'): kwargs['libx11'] = find_library("X11") _apply_env_var(kwargs, 'glversion', 'GLCONTEXT_GLVERSION', arg_type=int) _apply_env_var(kwargs, 'libgl', 'GLCONTEXT_LINUX_LIBGL') _apply_env_var(kwargs, 'libx11', 'GLCONTEXT_LINUX_LIBX11') kwargs = _strip_kwargs(kwargs, ['glversion', 'mode', 'libgl', 'libx11']) return x11.create_context(**kwargs) return create def _darwin(): """Create darwin/cgl context""" from glcontext import darwin def create(*args, **kwargs): return darwin.create_context(**_strip_kwargs(kwargs, ['mode'])) return create def _egl(): from glcontext import egl from ctypes.util import find_library def create(*args, **kwargs): if not kwargs.get('libgl'): kwargs['libgl'] = find_library('GL') if not kwargs.get('libegl'): kwargs['libegl'] = find_library('EGL') _apply_env_var(kwargs, 'device_index', 'GLCONTEXT_DEVICE_INDEX', arg_type=int) _apply_env_var(kwargs, 'glversion', 'GLCONTEXT_GLVERSION', arg_type=int) _apply_env_var(kwargs, 'libgl', 'GLCONTEXT_LINUX_LIBGL') _apply_env_var(kwargs, 'libegl', 'GLCONTEXT_LINUX_LIBEGL') kwargs = _strip_kwargs(kwargs, ['glversion', 'mode', 'libgl', 'libegl', 'device_index']) return egl.create_context(**kwargs) return create def _strip_kwargs(kwargs: dict, supported_args: list): """Strips away unwanted keyword arguments. The backends are using ``PyArg_ParseTupleAndKeywords`` to parse the incoming ``kwargs`` data. It's not well suited to handle additional arguments. - Removes None key arguments - Removes unsupported arguments """ return {k: v for k, v in kwargs.items() if v is not None and k in supported_args} def _apply_env_var(kwargs, arg_name, env_name, arg_type=str): """Injects an environment variable into the arg dict if present""" value = os.environ.get(env_name, kwargs.get(arg_name)) if value: kwargs[arg_name] = arg_type(value) moderngl-glcontext-1573e57/glcontext/darwin.cpp000066400000000000000000000115021451244733600216170ustar00rootroot00000000000000#include #include #include #include #import #import #import #include #include struct GLContext { PyObject_HEAD CGLContextObj ctx; int standalone; void * old_context; }; PyTypeObject * GLContext_type; GLContext * meth_create_context(PyObject * self, PyObject * args, PyObject * kwargs) { static char * keywords[] = {"mode", NULL}; const char * mode = "detect"; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|s", keywords, &mode)) { return NULL; } GLContext * res = PyObject_New(GLContext, GLContext_type); if (!strcmp(mode, "detect")) { res->standalone = false; res->ctx = CGLGetCurrentContext(); if (!res->ctx) { PyErr_Format(PyExc_Exception, "cannot detect OpenGL context"); return NULL; } return res; } if (!strcmp(mode, "standalone")) { res->standalone = true; GLint num_pixelformats = 0; CGLPixelFormatObj pixelformat = 0; CGLPixelFormatAttribute attribs[] = { kCGLPFAOpenGLProfile, (CGLPixelFormatAttribute)kCGLOGLPVersion_GL4_Core, (CGLPixelFormatAttribute)0, }; CGLChoosePixelFormat(attribs, &pixelformat, &num_pixelformats); if (!pixelformat) { CGLPixelFormatAttribute attribs[] = { kCGLPFAOpenGLProfile, (CGLPixelFormatAttribute)kCGLOGLPVersion_GL3_Core, (CGLPixelFormatAttribute)0, }; CGLChoosePixelFormat(attribs, &pixelformat, &num_pixelformats); if (!pixelformat) { CGLPixelFormatAttribute attribs[] = { (CGLPixelFormatAttribute)0, }; CGLChoosePixelFormat(attribs, &pixelformat, &num_pixelformats); } } if (!pixelformat) { PyErr_Format(PyExc_Exception, "cannot choose pixel format"); return NULL; } CGLContextObj cgl_context = NULL; CGLCreateContext(pixelformat, NULL, &cgl_context); CGLDestroyPixelFormat(pixelformat); if (!cgl_context) { PyErr_Format(PyExc_Exception, "cannot create OpenGL context"); return NULL; } res->ctx = cgl_context; CGLSetCurrentContext(cgl_context); return res; } PyErr_Format(PyExc_Exception, "unknown mode"); return NULL; } PyObject * GLContext_meth_load(GLContext * self, PyObject * arg) { PyObject * prefix = PyUnicode_FromString("_"); PyObject * prefixed = PyNumber_Add(prefix, arg); NSSymbol symbol = NULL; const char * method = PyUnicode_AsUTF8(prefixed); if (NSIsSymbolNameDefined(method)) { symbol = NSLookupAndBindSymbol(method); } Py_DECREF(prefixed); Py_DECREF(prefix); return PyLong_FromVoidPtr(symbol ? NSAddressOfSymbol(symbol) : NULL); } PyObject * GLContext_meth_enter(GLContext * self) { self->old_context = (void *)CGLGetCurrentContext(); CGLSetCurrentContext(self->ctx); Py_RETURN_NONE; } PyObject * GLContext_meth_exit(GLContext * self) { CGLSetCurrentContext((CGLContextObj)self->old_context); Py_RETURN_NONE; } PyObject * GLContext_meth_release(GLContext * self) { if (self->standalone) { CGLSetCurrentContext(NULL); CGLDestroyContext(self->ctx); } Py_RETURN_NONE; } void GLContext_dealloc(GLContext * self) { Py_TYPE(self)->tp_free(self); } PyMethodDef GLContext_methods[] = { {"load", (PyCFunction)GLContext_meth_load, METH_O, NULL}, {"load_opengl_function", (PyCFunction)GLContext_meth_load, METH_O, NULL}, {"release", (PyCFunction)GLContext_meth_release, METH_NOARGS, NULL}, {"__enter__", (PyCFunction)GLContext_meth_enter, METH_NOARGS, NULL}, {"__exit__", (PyCFunction)GLContext_meth_exit, METH_VARARGS, NULL}, {}, }; PyMemberDef GLContext_members[] = { {"standalone", T_BOOL, offsetof(GLContext, standalone), READONLY, NULL}, {}, }; PyType_Slot GLContext_slots[] = { {Py_tp_methods, GLContext_methods}, {Py_tp_members, GLContext_members}, {Py_tp_dealloc, (void *)GLContext_dealloc}, {}, }; PyType_Spec GLContext_spec = {"darwin.GLContext", sizeof(GLContext), 0, Py_TPFLAGS_DEFAULT, GLContext_slots}; PyMethodDef module_methods[] = { {"create_context", (PyCFunction)meth_create_context, METH_VARARGS | METH_KEYWORDS, NULL}, {}, }; PyModuleDef module_def = {PyModuleDef_HEAD_INIT, "darwin", NULL, -1, module_methods}; extern "C" PyObject * PyInit_darwin() { PyObject * module = PyModule_Create(&module_def); GLContext_type = (PyTypeObject *)PyType_FromSpec(&GLContext_spec); PyModule_AddObject(module, "GLContext", (PyObject *)GLContext_type); return module; } moderngl-glcontext-1573e57/glcontext/egl.cpp000066400000000000000000000341661451244733600211150ustar00rootroot00000000000000#include #include #include struct Display; typedef unsigned int EGLenum; typedef int EGLint; typedef unsigned int EGLBoolean; typedef Display * EGLNativeDisplayType; typedef void * EGLConfig; typedef void * EGLSurface; typedef void * EGLContext; typedef void * EGLDeviceEXT; typedef void * EGLDisplay; #define EGL_DEFAULT_DISPLAY 0 #define EGL_NO_CONTEXT 0 #define EGL_NO_SURFACE 0 #define EGL_NO_DISPLAY 0 #define EGL_PBUFFER_BIT 0x0001 #define EGL_WINDOW_BIT 0x0004 #define EGL_RENDERABLE_TYPE 0x3040 #define EGL_NONE 0x3038 #define EGL_OPENGL_BIT 0x0008 #define EGL_BLUE_SIZE 0x3022 #define EGL_DEPTH_SIZE 0x3025 #define EGL_RED_SIZE 0x3024 #define EGL_GREEN_SIZE 0x3023 #define EGL_SURFACE_TYPE 0x3033 #define EGL_OPENGL_API 0x30A2 #define EGL_WIDTH 0x3057 #define EGL_HEIGHT 0x3056 #define EGL_SUCCESS 0x3000 #define EGL_CONTEXT_MAJOR_VERSION 0x3098 #define EGL_CONTEXT_MINOR_VERSION 0x30FB #define EGL_CONTEXT_OPENGL_PROFILE_MASK 0x30FD #define EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT 0x00000001 #define EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE 0x31B1 #define EGL_PLATFORM_DEVICE_EXT 0x313F #define EGL_PLATFORM_WAYLAND_EXT 0x31D8 #define EGL_PLATFORM_X11_EXT 0x31D5 #define EGL_DRAW 0x3059 #define EGL_READ 0x305A typedef EGLint (* m_eglGetErrorProc)(); typedef EGLDisplay (* m_eglGetDisplayProc)(EGLNativeDisplayType); typedef EGLBoolean (* m_eglInitializeProc)(EGLDisplay, EGLint *, EGLint *); typedef EGLBoolean (* m_eglChooseConfigProc)(EGLDisplay, const EGLint *, EGLConfig *, EGLint, EGLint *); typedef EGLBoolean (* m_eglBindAPIProc)(EGLenum); typedef EGLContext (* m_eglCreateContextProc)(EGLDisplay, EGLConfig, EGLContext, const EGLint *); typedef EGLBoolean (* m_eglDestroyContextProc)(EGLDisplay, EGLContext); typedef EGLBoolean (* m_eglMakeCurrentProc)(EGLDisplay, EGLSurface, EGLSurface, EGLContext); typedef void (* (* m_eglGetProcAddressProc)(const char *))(); typedef EGLBoolean (* m_eglQueryDevicesEXTProc)(EGLint, EGLDeviceEXT *, EGLint *); typedef EGLDisplay (* m_eglGetPlatformDisplayEXTProc) (EGLenum, void *, const EGLint *); typedef EGLContext (* m_eglGetCurrentContextProc) (void); typedef EGLSurface (* m_eglGetCurrentSurfaceProc ) (EGLint readdraw); typedef EGLDisplay (* m_eglGetCurrentDisplayProc )(void); struct GLContext { PyObject_HEAD void * libgl; void * libegl; EGLContext ctx; EGLDisplay dpy; EGLConfig cfg; EGLSurface wnd; int standalone; m_eglGetErrorProc m_eglGetError; m_eglGetDisplayProc m_eglGetDisplay; m_eglInitializeProc m_eglInitialize; m_eglChooseConfigProc m_eglChooseConfig; m_eglBindAPIProc m_eglBindAPI; m_eglCreateContextProc m_eglCreateContext; m_eglDestroyContextProc m_eglDestroyContext; m_eglMakeCurrentProc m_eglMakeCurrent; m_eglGetProcAddressProc m_eglGetProcAddress; m_eglQueryDevicesEXTProc m_eglQueryDevicesEXT; m_eglGetPlatformDisplayEXTProc m_eglGetPlatformDisplayEXT; m_eglGetCurrentContextProc m_eglGetCurrentContext; m_eglGetCurrentSurfaceProc m_eglGetCurrentSurface; m_eglGetCurrentDisplayProc m_eglGetCurrentDisplay; }; PyTypeObject * GLContext_type; GLContext * meth_create_context(PyObject * self, PyObject * args, PyObject * kwargs) { static char * keywords[] = {"mode", "libgl", "libegl", "glversion", "device_index", NULL}; const char * mode = "standalone"; const char * libgl = "libGL.so"; const char * libegl = "libEGL.so"; int glversion = 330; int device_index = 0; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|sssii", keywords, &mode, &libgl, &libegl, &glversion, &device_index)) { return NULL; } GLContext * res = PyObject_New(GLContext, GLContext_type); res->libgl = dlopen(libgl, RTLD_LAZY); if (!res->libgl) { PyErr_Format(PyExc_Exception, "%s not loaded", libgl); return NULL; } res->libegl = dlopen(libegl, RTLD_LAZY); if (!res->libegl) { PyErr_Format(PyExc_Exception, "%s not loaded", libegl); return NULL; } res->m_eglGetError = (m_eglGetErrorProc)dlsym(res->libegl, "eglGetError"); if (!res->m_eglGetError) { PyErr_Format(PyExc_Exception, "eglGetError not found"); return NULL; } res->m_eglGetDisplay = (m_eglGetDisplayProc)dlsym(res->libegl, "eglGetDisplay"); if (!res->m_eglGetDisplay) { PyErr_Format(PyExc_Exception, "eglGetDisplay not found"); return NULL; } res->m_eglInitialize = (m_eglInitializeProc)dlsym(res->libegl, "eglInitialize"); if (!res->m_eglInitialize) { PyErr_Format(PyExc_Exception, "eglInitialize not found"); return NULL; } res->m_eglChooseConfig = (m_eglChooseConfigProc)dlsym(res->libegl, "eglChooseConfig"); if (!res->m_eglChooseConfig) { PyErr_Format(PyExc_Exception, "eglChooseConfig not found"); return NULL; } res->m_eglBindAPI = (m_eglBindAPIProc)dlsym(res->libegl, "eglBindAPI"); if (!res->m_eglBindAPI) { PyErr_Format(PyExc_Exception, "eglBindAPI not found"); return NULL; } res->m_eglCreateContext = (m_eglCreateContextProc)dlsym(res->libegl, "eglCreateContext"); if (!res->m_eglCreateContext) { PyErr_Format(PyExc_Exception, "eglCreateContext not found"); return NULL; } res->m_eglDestroyContext = (m_eglDestroyContextProc)dlsym(res->libegl, "eglDestroyContext"); if (!res->m_eglDestroyContext) { PyErr_Format(PyExc_Exception, "eglDestroyContext not found"); return NULL; } res->m_eglMakeCurrent = (m_eglMakeCurrentProc)dlsym(res->libegl, "eglMakeCurrent"); if (!res->m_eglMakeCurrent) { PyErr_Format(PyExc_Exception, "eglMakeCurrent not found"); return NULL; } res->m_eglGetProcAddress = (m_eglGetProcAddressProc)dlsym(res->libegl, "eglGetProcAddress"); if (!res->m_eglGetProcAddress) { PyErr_Format(PyExc_Exception, "eglGetProcAddress not found"); return NULL; } res->m_eglQueryDevicesEXT = (m_eglQueryDevicesEXTProc)res->m_eglGetProcAddress("eglQueryDevicesEXT"); if (!res->m_eglQueryDevicesEXT) { PyErr_Format(PyExc_Exception, "eglQueryDevicesEXT not found"); return NULL; } res->m_eglGetPlatformDisplayEXT = (m_eglGetPlatformDisplayEXTProc)res->m_eglGetProcAddress("eglGetPlatformDisplayEXT"); if (!res->m_eglGetPlatformDisplayEXT) { PyErr_Format(PyExc_Exception, "eglGetPlatformDisplayEXT not found"); return NULL; } res->m_eglGetCurrentDisplay = (m_eglGetCurrentDisplayProc)res->m_eglGetProcAddress("eglGetCurrentDisplay"); if (!res->m_eglGetCurrentDisplay) { PyErr_Format(PyExc_Exception, "eglGetCurrentDisplay not found"); return NULL; } res->m_eglGetCurrentContext = (m_eglGetCurrentContextProc)res->m_eglGetProcAddress("eglGetCurrentContext"); if (!res->m_eglGetCurrentContext) { PyErr_Format(PyExc_Exception, "eglGetCurrentContext not found"); return NULL; } res->m_eglGetCurrentSurface = (m_eglGetCurrentSurfaceProc)res->m_eglGetProcAddress("eglGetCurrentSurface"); if (!res->m_eglGetCurrentSurface) { PyErr_Format(PyExc_Exception, "eglGetCurrentSurfaceProc not found"); return NULL; } if (!strcmp(mode, "standalone")) { res->standalone = true; res->wnd = EGL_NO_SURFACE; EGLint num_devices; if (!res->m_eglQueryDevicesEXT(0, NULL, &num_devices)) { PyErr_Format(PyExc_Exception, "eglQueryDevicesEXT failed (0x%x)", res->m_eglGetError()); return NULL; } if (device_index >= num_devices) { PyErr_Format(PyExc_Exception, "requested device index %d, but found %d devices", device_index, num_devices); return NULL; } EGLDeviceEXT * devices = (EGLDeviceEXT *)malloc(sizeof(EGLDeviceEXT) * num_devices); if (!res->m_eglQueryDevicesEXT(num_devices, devices, &num_devices)) { PyErr_Format(PyExc_Exception, "eglQueryDevicesEXT failed (0x%x)", res->m_eglGetError()); free(devices); return NULL; } EGLDeviceEXT device = devices[device_index]; free(devices); res->dpy = res->m_eglGetPlatformDisplayEXT(EGL_PLATFORM_DEVICE_EXT, device, 0); if (res->dpy == EGL_NO_DISPLAY) { PyErr_Format(PyExc_Exception, "eglGetPlatformDisplayEXT failed (0x%x)", res->m_eglGetError()); return NULL; } EGLint major, minor; if (!res->m_eglInitialize(res->dpy, &major, &minor)) { PyErr_Format(PyExc_Exception, "eglInitialize failed (0x%x)", res->m_eglGetError()); return NULL; } EGLint config_attribs[] = { EGL_SURFACE_TYPE, EGL_PBUFFER_BIT, EGL_BLUE_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_RED_SIZE, 8, EGL_DEPTH_SIZE, 8, EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT, EGL_NONE }; EGLint num_configs = 0; if (!res->m_eglChooseConfig(res->dpy, config_attribs, &res->cfg, 1, &num_configs)) { PyErr_Format(PyExc_Exception, "eglChooseConfig failed (0x%x)", res->m_eglGetError()); return NULL; } if (!res->m_eglBindAPI(EGL_OPENGL_API)) { PyErr_Format(PyExc_Exception, "eglBindAPI failed (0x%x)", res->m_eglGetError()); return NULL; } int ctxattribs[] = { EGL_CONTEXT_MAJOR_VERSION, glversion / 100 % 10, EGL_CONTEXT_MINOR_VERSION, glversion / 10 % 10, EGL_CONTEXT_OPENGL_PROFILE_MASK, EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT, // EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE, 1, EGL_NONE, }; res->ctx = res->m_eglCreateContext(res->dpy, res->cfg, EGL_NO_CONTEXT, ctxattribs); if (!res->ctx) { PyErr_Format(PyExc_Exception, "eglCreateContext failed (0x%x)", res->m_eglGetError()); return NULL; } res->m_eglMakeCurrent(res->dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, res->ctx); return res; } if (!strcmp(mode, "share")) { res->standalone = false; EGLContext ctx_share = res->m_eglGetCurrentContext(); if (!ctx_share) { PyErr_Format(PyExc_Exception, "(share) eglGetCurrentContext: cannot detect OpenGL context"); return NULL; } res->wnd = res->m_eglGetCurrentSurface(EGL_DRAW); if (!res->wnd) { PyErr_Format(PyExc_Exception, "(share) m_eglGetCurrentSurface failed (0x%x)", res->m_eglGetError()); return NULL; } res->dpy = res->m_eglGetCurrentDisplay(); if (res->dpy == EGL_NO_DISPLAY) { PyErr_Format(PyExc_Exception, "eglGetCurrentDisplay failed (0x%x)", res->m_eglGetError()); return NULL; } EGLint config_attribs[] = { EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_BLUE_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_RED_SIZE, 8, EGL_DEPTH_SIZE, 24, EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT, EGL_NONE }; EGLint num_configs = 0; if (!res->m_eglChooseConfig(res->dpy, config_attribs, &res->cfg, 1, &num_configs)) { PyErr_Format(PyExc_Exception, "eglChooseConfig failed (0x%x)", res->m_eglGetError()); return NULL; } if (!res->m_eglBindAPI(EGL_OPENGL_API)) { PyErr_Format(PyExc_Exception, "eglBindAPI failed (0x%x)", res->m_eglGetError()); return NULL; } int ctxattribs[] = { EGL_CONTEXT_MAJOR_VERSION, glversion / 100 % 10, EGL_CONTEXT_MINOR_VERSION, glversion / 10 % 10, EGL_CONTEXT_OPENGL_PROFILE_MASK, EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT, // EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE, 1, EGL_NONE, }; res->ctx = res->m_eglCreateContext(res->dpy, res->cfg, ctx_share, ctxattribs); if (!res->ctx) { PyErr_Format(PyExc_Exception, "eglCreateContext failed (0x%x)", res->m_eglGetError()); return NULL; } res->m_eglMakeCurrent(res->dpy, res->wnd, res->wnd, res->ctx); return res; } PyErr_Format(PyExc_Exception, "unknown mode"); return NULL; } PyObject * GLContext_meth_load(GLContext * self, PyObject * arg) { const char * method = PyUnicode_AsUTF8(arg); void * proc = (void *)dlsym(self->libgl, method); if (!proc) { proc = (void *)self->m_eglGetProcAddress(method); } return PyLong_FromVoidPtr(proc); } PyObject * GLContext_meth_enter(GLContext * self) { self->m_eglMakeCurrent(self->dpy, self->wnd, self->wnd, self->ctx); Py_RETURN_NONE; } PyObject * GLContext_meth_exit(GLContext * self) { self->m_eglMakeCurrent(self->dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); Py_RETURN_NONE; } PyObject * GLContext_meth_release(GLContext * self) { self->m_eglDestroyContext(self->dpy, self->ctx); Py_RETURN_NONE; } void GLContext_dealloc(GLContext * self) { Py_TYPE(self)->tp_free(self); } PyMethodDef GLContext_methods[] = { {"load", (PyCFunction)GLContext_meth_load, METH_O, NULL}, {"load_opengl_function", (PyCFunction)GLContext_meth_load, METH_O, NULL}, {"release", (PyCFunction)GLContext_meth_release, METH_NOARGS, NULL}, {"__enter__", (PyCFunction)GLContext_meth_enter, METH_NOARGS, NULL}, {"__exit__", (PyCFunction)GLContext_meth_exit, METH_VARARGS, NULL}, {}, }; PyMemberDef GLContext_members[] = { {"standalone", T_BOOL, offsetof(GLContext, standalone), READONLY, NULL}, {}, }; PyType_Slot GLContext_slots[] = { {Py_tp_methods, GLContext_methods}, {Py_tp_members, GLContext_members}, {Py_tp_dealloc, (void *)GLContext_dealloc}, {}, }; PyType_Spec GLContext_spec = {"egl.GLContext", sizeof(GLContext), 0, Py_TPFLAGS_DEFAULT, GLContext_slots}; PyMethodDef module_methods[] = { {"create_context", (PyCFunction)meth_create_context, METH_VARARGS | METH_KEYWORDS, NULL}, {}, }; PyModuleDef module_def = {PyModuleDef_HEAD_INIT, "egl", NULL, -1, module_methods}; extern "C" PyObject * PyInit_egl() { PyObject * module = PyModule_Create(&module_def); GLContext_type = (PyTypeObject *)PyType_FromSpec(&GLContext_spec); PyModule_AddObject(module, "GLContext", (PyObject *)GLContext_type); return module; } moderngl-glcontext-1573e57/glcontext/empty.cpp000066400000000000000000000035331451244733600214760ustar00rootroot00000000000000#include struct GLContext { PyObject_HEAD }; PyTypeObject * GLContext_type; GLContext * meth_create_context(PyObject * self, PyObject * args, PyObject * kwargs) { static char * keywords[] = {NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "", keywords)) { return NULL; } GLContext * res = PyObject_New(GLContext, GLContext_type); return res; } PyObject * GLContext_meth_load(GLContext * self, PyObject * arg) { return PyLong_FromVoidPtr(NULL); } PyObject * GLContext_meth_enter(GLContext * self) { Py_RETURN_NONE; } PyObject * GLContext_meth_exit(GLContext * self) { Py_RETURN_NONE; } PyObject * GLContext_meth_release(GLContext * self) { Py_RETURN_NONE; } void GLContext_dealloc(GLContext * self) { Py_TYPE(self)->tp_free(self); } PyMethodDef GLContext_methods[] = { {"load_opengl_function", (PyCFunction)GLContext_meth_load, METH_O, NULL}, {"release", (PyCFunction)GLContext_meth_release, METH_NOARGS, NULL}, {"__enter__", (PyCFunction)GLContext_meth_enter, METH_NOARGS, NULL}, {"__exit__", (PyCFunction)GLContext_meth_exit, METH_VARARGS, NULL}, {}, }; PyType_Slot GLContext_slots[] = { {Py_tp_methods, GLContext_methods}, {Py_tp_dealloc, (void *)GLContext_dealloc}, {}, }; PyType_Spec GLContext_spec = {"empty.GLContext", sizeof(GLContext), 0, Py_TPFLAGS_DEFAULT, GLContext_slots}; PyMethodDef module_methods[] = { {"create_context", (PyCFunction)meth_create_context, METH_VARARGS | METH_KEYWORDS, NULL}, {}, }; PyModuleDef module_def = {PyModuleDef_HEAD_INIT, "empty", NULL, -1, module_methods}; extern "C" PyObject * PyInit_empty() { PyObject * module = PyModule_Create(&module_def); GLContext_type = (PyTypeObject *)PyType_FromSpec(&GLContext_spec); PyModule_AddObject(module, "GLContext", (PyObject *)GLContext_type); return module; } moderngl-glcontext-1573e57/glcontext/empty.py000066400000000000000000000004321451244733600213370ustar00rootroot00000000000000class GLContext: def __init__(self): pass def load_opengl_function(self, name): return 0 def __enter__(self): pass def __exit__(self, *args): pass def release(self): pass def create_context(): return GLContext() moderngl-glcontext-1573e57/glcontext/headless.cpp000066400000000000000000000060131451244733600221240ustar00rootroot00000000000000#include #include #include int num_devices; EGLDeviceEXT devices[64]; EGLContext context; EGLDisplay display; EGLConfig config; PyObject * meth_devices(PyObject * self) { PFNEGLQUERYDEVICESEXTPROC eglQueryDevicesEXT = (PFNEGLQUERYDEVICESEXTPROC)eglGetProcAddress("eglQueryDevicesEXT"); PFNEGLQUERYDEVICESTRINGEXTPROC eglQueryDeviceStringEXT = (PFNEGLQUERYDEVICESTRINGEXTPROC)eglGetProcAddress("eglQueryDeviceStringEXT"); if (!eglQueryDevicesEXT(0, NULL, &num_devices)) { return NULL; } if (!eglQueryDevicesEXT(num_devices, devices, &num_devices)) { return NULL; } PyObject * res = PyList_New(num_devices); for (int i = 0; i < num_devices; ++i) { const char * egl_extensions = eglQueryDeviceStringEXT(devices[i], EGL_EXTENSIONS); PyObject * temp = PyUnicode_FromString(egl_extensions ? egl_extensions : ""); PyObject * extensions = PyObject_CallMethod(temp, "split", NULL); Py_DECREF(temp); PyList_SetItem(res, i, Py_BuildValue("{sisN}", "device", i, "extensions", extensions)); } return res; } PyObject * meth_init(PyObject * self, PyObject * args, PyObject * kwargs) { const char * keywords[] = {"device", NULL}; int device = 0; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i", (char **)keywords, &device)) { return NULL; } if (device > num_devices) { return NULL; } display = eglGetPlatformDisplay(EGL_PLATFORM_DEVICE_EXT, devices[device], 0); if (display == EGL_NO_DISPLAY) { return NULL; } if (!eglInitialize(display, NULL, NULL)) { return NULL; } int config_attribs[] = { EGL_SURFACE_TYPE, EGL_PBUFFER_BIT, EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT, EGL_NONE, }; int num_configs = 0; if (!eglChooseConfig(display, config_attribs, &config, 1, &num_configs)) { return NULL; } if (!eglBindAPI(EGL_OPENGL_API)) { return NULL; } int context_attribs[] = { EGL_CONTEXT_OPENGL_PROFILE_MASK, EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT, EGL_NONE, }; context = eglCreateContext(display, config, EGL_NO_CONTEXT, context_attribs); if (!context) { return NULL; } eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, context); Py_RETURN_NONE; } PyObject * meth_load_opengl_function(PyObject * self, PyObject * arg) { if (!PyUnicode_CheckExact(arg)) { return NULL; } const char * name = PyUnicode_AsUTF8(arg); return PyLong_FromVoidPtr((void *)eglGetProcAddress(name)); } PyMethodDef module_methods[] = { {"devices", (PyCFunction)meth_devices, METH_NOARGS}, {"init", (PyCFunction)meth_init, METH_VARARGS | METH_KEYWORDS}, {"load_opengl_function", (PyCFunction)meth_load_opengl_function, METH_O}, {}, }; PyModuleDef module_def = {PyModuleDef_HEAD_INIT, "headless", NULL, -1, module_methods}; extern "C" PyObject * PyInit_headless() { PyObject * module = PyModule_Create(&module_def); return module; } moderngl-glcontext-1573e57/glcontext/wgl.cpp000066400000000000000000000262241451244733600211330ustar00rootroot00000000000000#include #include #include #define WGL_CONTEXT_PROFILE_MASK 0x9126 #define WGL_CONTEXT_CORE_PROFILE_BIT 0x0001 #define WGL_CONTEXT_MAJOR_VERSION 0x2091 #define WGL_CONTEXT_MINOR_VERSION 0x2092 typedef HGLRC (WINAPI * m_wglGetCurrentContextProc)(); typedef HDC (WINAPI * m_wglGetCurrentDCProc)(); typedef HGLRC (WINAPI * m_wglCreateContextProc)(HDC); typedef BOOL (WINAPI * m_wglDeleteContextProc)(HGLRC); typedef PROC (WINAPI * m_wglGetProcAddressProc)(LPCSTR); typedef BOOL (WINAPI * m_wglMakeCurrentProc)(HDC, HGLRC); typedef HGLRC (WINAPI * m_wglCreateContextAttribsARBProc)(HDC, HGLRC, const int *); typedef BOOL (WINAPI * m_wglSwapIntervalEXTProc)(int); HINSTANCE hinst; struct GLContext { PyObject_HEAD HMODULE libgl; HWND hwnd; HDC hdc; HGLRC hrc; int standalone; void * old_context; void * old_display; m_wglGetCurrentContextProc m_wglGetCurrentContext; m_wglGetCurrentDCProc m_wglGetCurrentDC; m_wglCreateContextProc m_wglCreateContext; m_wglDeleteContextProc m_wglDeleteContext; m_wglGetProcAddressProc m_wglGetProcAddress; m_wglMakeCurrentProc m_wglMakeCurrent; m_wglCreateContextAttribsARBProc m_wglCreateContextAttribsARB; m_wglSwapIntervalEXTProc m_wglSwapIntervalEXT; }; PyTypeObject * GLContext_type; GLContext * meth_create_context(PyObject * self, PyObject * args, PyObject * kwargs) { static char * keywords[] = {"mode", "libgl", "glversion", NULL}; const char * mode = "detect"; const char * libgl = "opengl32.dll"; int glversion = 330; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|ssi", keywords, &mode, &libgl, &glversion)) { return NULL; } GLContext * res = PyObject_New(GLContext, GLContext_type); // The mode parameter is required for dll's specifed as libgl // to load successfully along with its dependencies on Python 3.8+. // This is due to the introduction of using a short dll load path // inside of Python 3.8+. int load_mode = LOAD_LIBRARY_SEARCH_DEFAULT_DIRS; // Search default dirs first // Check whether libgl contains `/` or `\\`. // We can treat that `libgl` would be absolute in that case. if (strchr(libgl, '/') || strchr(libgl, '\\')) { // Search the dirs in which the dll is located load_mode |= LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR; } res->libgl = LoadLibraryEx(libgl, NULL, (DWORD)load_mode); if (!res->libgl) { DWORD last_error = GetLastError(); PyErr_Format(PyExc_Exception, "%s not loaded. Error code: %ld.", libgl, last_error); return NULL; } res->m_wglGetCurrentContext = (m_wglGetCurrentContextProc)GetProcAddress(res->libgl, "wglGetCurrentContext"); if (!res->m_wglGetCurrentContext) { PyErr_Format(PyExc_Exception, "wglGetCurrentContext not found"); return NULL; } res->m_wglGetCurrentDC = (m_wglGetCurrentDCProc)GetProcAddress(res->libgl, "wglGetCurrentDC"); if (!res->m_wglGetCurrentDC) { PyErr_Format(PyExc_Exception, "wglGetCurrentDC not found"); return NULL; } res->m_wglCreateContext = (m_wglCreateContextProc)GetProcAddress(res->libgl, "wglCreateContext"); if (!res->m_wglCreateContext) { PyErr_Format(PyExc_Exception, "wglCreateContext not found"); return NULL; } res->m_wglDeleteContext = (m_wglDeleteContextProc)GetProcAddress(res->libgl, "wglDeleteContext"); if (!res->m_wglDeleteContext) { PyErr_Format(PyExc_Exception, "wglDeleteContext not found"); return NULL; } res->m_wglGetProcAddress = (m_wglGetProcAddressProc)GetProcAddress(res->libgl, "wglGetProcAddress"); if (!res->m_wglGetProcAddress) { PyErr_Format(PyExc_Exception, "wglGetProcAddress not found"); return NULL; } res->m_wglMakeCurrent = (m_wglMakeCurrentProc)GetProcAddress(res->libgl, "wglMakeCurrent"); if (!res->m_wglMakeCurrent) { PyErr_Format(PyExc_Exception, "wglMakeCurrent not found"); return NULL; } if (!strcmp(mode, "detect")) { res->hwnd = NULL; res->hrc = res->m_wglGetCurrentContext(); if (!res->hrc) { PyErr_Format(PyExc_Exception, "cannot detect OpenGL context"); return NULL; } res->hdc = res->m_wglGetCurrentDC(); if (!res->hdc) { PyErr_Format(PyExc_Exception, "wglGetCurrentDC failed"); return NULL; } return res; } if (!strcmp(mode, "share")) { res->hwnd = NULL; res->standalone = true; HGLRC hrc_share = res->m_wglGetCurrentContext(); if (!hrc_share) { PyErr_Format(PyExc_Exception, "cannot detect OpenGL context"); return NULL; } res->hdc = res->m_wglGetCurrentDC(); if (!res->hdc) { PyErr_Format(PyExc_Exception, "wglGetCurrentDC failed"); return NULL; } FARPROC proc = res->m_wglGetProcAddress("wglCreateContextAttribsARB"); res->m_wglCreateContextAttribsARB = (m_wglCreateContextAttribsARBProc)proc; if (!res->m_wglCreateContextAttribsARB) { PyErr_Format(PyExc_Exception, "wglCreateContextAttribsARB failed"); return NULL; } res->m_wglMakeCurrent(NULL, NULL); int attribs[] = { WGL_CONTEXT_PROFILE_MASK, WGL_CONTEXT_CORE_PROFILE_BIT, WGL_CONTEXT_MAJOR_VERSION, glversion / 100 % 10, WGL_CONTEXT_MINOR_VERSION, glversion / 10 % 10, 0, 0, }; res->hrc = res->m_wglCreateContextAttribsARB(res->hdc, hrc_share, attribs); if (!res->hrc) { PyErr_Format(PyExc_Exception, "wglCreateContextAttribsARB failed"); return NULL; } if (!res->m_wglMakeCurrent(res->hdc, res->hrc)) { PyErr_Format(PyExc_Exception, "wglMakeCurrent failed"); return NULL; } return res; } if (!strcmp(mode, "standalone")) { res->standalone = true; res->hwnd = CreateWindow("glcontext", NULL, 0, 0, 0, 0, 0, NULL, NULL, hinst, NULL); if (!res->hwnd) { PyErr_Format(PyExc_Exception, "CreateWindow failed"); return NULL; } res->hdc = GetDC(res->hwnd); if (!res->hdc) { PyErr_Format(PyExc_Exception, "GetDC failed"); return NULL; } PIXELFORMATDESCRIPTOR pfd = { sizeof(PIXELFORMATDESCRIPTOR), 1, PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_GENERIC_ACCELERATED | PFD_DOUBLEBUFFER, 0, 24, }; int pixelformat = ChoosePixelFormat(res->hdc, &pfd); if (!pixelformat) { PyErr_Format(PyExc_Exception, "ChoosePixelFormat failed"); return NULL; } if (!SetPixelFormat(res->hdc, pixelformat, &pfd)) { PyErr_Format(PyExc_Exception, "SetPixelFormat failed"); return NULL; } HGLRC hrc_share = res->m_wglCreateContext(res->hdc); if (!hrc_share) { PyErr_Format(PyExc_Exception, "wglCreateContext failed"); return NULL; } if (!res->m_wglMakeCurrent(res->hdc, hrc_share)) { PyErr_Format(PyExc_Exception, "wglMakeCurrent failed"); return NULL; } FARPROC proc = res->m_wglGetProcAddress("wglCreateContextAttribsARB"); res->m_wglCreateContextAttribsARB = (m_wglCreateContextAttribsARBProc)proc; if (!res->m_wglCreateContextAttribsARB) { PyErr_Format(PyExc_Exception, "wglCreateContextAttribsARB not found"); return NULL; } res->m_wglMakeCurrent(NULL, NULL); if (!res->m_wglDeleteContext(hrc_share)) { PyErr_Format(PyExc_Exception, "wglDeleteContext failed"); return NULL; } int attribs[] = { WGL_CONTEXT_PROFILE_MASK, WGL_CONTEXT_CORE_PROFILE_BIT, WGL_CONTEXT_MAJOR_VERSION, glversion / 100 % 10, WGL_CONTEXT_MINOR_VERSION, glversion / 10 % 10, 0, 0, }; res->hrc = res->m_wglCreateContextAttribsARB(res->hdc, NULL, attribs); if (!res->hrc) { PyErr_Format(PyExc_Exception, "wglCreateContextAttribsARB failed"); return NULL; } if (!res->m_wglMakeCurrent(res->hdc, res->hrc)) { PyErr_Format(PyExc_Exception, "wglMakeCurrent failed"); return NULL; } return res; } PyErr_Format(PyExc_Exception, "unknown mode"); return NULL; } PyObject * GLContext_meth_load(GLContext * self, PyObject * arg) { const char * name = PyUnicode_AsUTF8(arg); void * proc = (void *)GetProcAddress(self->libgl, name); if (!proc) { proc = (void *)self->m_wglGetProcAddress(name); } return PyLong_FromVoidPtr(proc); } PyObject * GLContext_meth_enter(GLContext * self) { self->old_context = (void *)self->m_wglGetCurrentContext(); self->old_display = (void *)self->m_wglGetCurrentDC(); self->m_wglMakeCurrent(self->hdc, self->hrc); Py_RETURN_NONE; } PyObject * GLContext_meth_exit(GLContext * self) { self->m_wglMakeCurrent((HDC)self->old_display, (HGLRC)self->old_context); Py_RETURN_NONE; } PyObject * GLContext_meth_release(GLContext * self) { self->m_wglMakeCurrent(NULL, NULL); self->m_wglDeleteContext(self->hrc); if (self->standalone) { ReleaseDC(self->hwnd, self->hdc); DestroyWindow(self->hwnd); } Py_RETURN_NONE; } void GLContext_dealloc(GLContext * self) { Py_TYPE(self)->tp_free(self); } PyMethodDef GLContext_methods[] = { {"load", (PyCFunction)GLContext_meth_load, METH_O, NULL}, {"load_opengl_function", (PyCFunction)GLContext_meth_load, METH_O, NULL}, {"release", (PyCFunction)GLContext_meth_release, METH_NOARGS, NULL}, {"__enter__", (PyCFunction)GLContext_meth_enter, METH_NOARGS, NULL}, {"__exit__", (PyCFunction)GLContext_meth_exit, METH_VARARGS, NULL}, {}, }; PyMemberDef GLContext_members[] = { {"standalone", T_BOOL, offsetof(GLContext, standalone), READONLY, NULL}, {}, }; PyType_Slot GLContext_slots[] = { {Py_tp_methods, GLContext_methods}, {Py_tp_members, GLContext_members}, {Py_tp_dealloc, (void *)GLContext_dealloc}, {}, }; PyType_Spec GLContext_spec = {"wgl.GLContext", sizeof(GLContext), 0, Py_TPFLAGS_DEFAULT, GLContext_slots}; PyMethodDef module_methods[] = { {"create_context", (PyCFunction)meth_create_context, METH_VARARGS | METH_KEYWORDS, NULL}, {}, }; PyModuleDef module_def = {PyModuleDef_HEAD_INIT, "wgl", NULL, -1, module_methods}; extern "C" PyObject * PyInit_wgl() { PyObject * module = PyModule_Create(&module_def); GLContext_type = (PyTypeObject *)PyType_FromSpec(&GLContext_spec); PyModule_AddObject(module, "GLContext", (PyObject *)GLContext_type); return module; } BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { if (fdwReason == DLL_PROCESS_ATTACH) { hinst = hinstDLL; WNDCLASSEX wnd_class = { sizeof(WNDCLASSEX), CS_OWNDC, DefWindowProc, 0, 0, hinst, NULL, NULL, NULL, NULL, "glcontext", NULL, }; if (!RegisterClassEx(&wnd_class)) { return NULL; } } return true; } moderngl-glcontext-1573e57/glcontext/windowed.cpp000066400000000000000000000036211451244733600221560ustar00rootroot00000000000000#include #if defined(_WIN32) || defined(_WIN64) #include PyObject * meth_load_opengl_function(PyObject * self, PyObject * arg) { if (!PyUnicode_CheckExact(arg)) { return NULL; } HMODULE module = GetModuleHandle("opengl32"); if (!module) { return NULL; } const char * name = PyUnicode_AsUTF8(arg); void * proc = (void *)GetProcAddress(module, name); if (!proc) { proc = wglGetProcAddress(name); } return PyLong_FromVoidPtr(proc); } #elif defined(__APPLE__) #include #include #import #import #import #include #include PyObject * meth_load_opengl_function(PyObject * self, PyObject * arg) { if (!PyUnicode_CheckExact(arg)) { return NULL; } PyObject * prefix = PyUnicode_FromString("_"); PyObject * prefixed = PyNumber_Add(prefix, arg); NSSymbol symbol = NULL; const char * method = PyUnicode_AsUTF8(prefixed); if (NSIsSymbolNameDefined(method)) { symbol = NSLookupAndBindSymbol(method); } Py_DECREF(prefixed); Py_DECREF(prefix); return PyLong_FromVoidPtr(symbol ? NSAddressOfSymbol(symbol) : NULL); } #else #include #include PyObject * meth_load_opengl_function(PyObject * self, PyObject * arg) { if (!PyUnicode_CheckExact(arg)) { return NULL; } const char * name = PyUnicode_AsUTF8(arg); return PyLong_FromVoidPtr((void *)glXGetProcAddress((unsigned char *)name)); } #endif PyMethodDef module_methods[] = { {"load_opengl_function", (PyCFunction)meth_load_opengl_function, METH_O}, {}, }; PyModuleDef module_def = {PyModuleDef_HEAD_INIT, "windowed", NULL, -1, module_methods}; extern "C" PyObject * PyInit_windowed() { PyObject * module = PyModule_Create(&module_def); return module; } moderngl-glcontext-1573e57/glcontext/x11.cpp000066400000000000000000000433351451244733600207550ustar00rootroot00000000000000#include #include #include #include #include #define GLX_CONTEXT_MAJOR_VERSION 0x2091 #define GLX_CONTEXT_MINOR_VERSION 0x2092 #define GLX_CONTEXT_PROFILE_MASK 0x9126 #define GLX_CONTEXT_CORE_PROFILE_BIT 0x0001 #define GLX_RGBA 4 #define GLX_DOUBLEBUFFER 5 #define GLX_RED_SIZE 8 #define GLX_GREEN_SIZE 9 #define GLX_BLUE_SIZE 10 #define GLX_DEPTH_SIZE 12 typedef struct __GLXcontextRec * GLXContext; typedef struct __GLXFBConfigRec * GLXFBConfig; typedef XID GLXDrawable; typedef GLXFBConfig * (* m_glXChooseFBConfigProc)(Display *, int, const int *, int *); typedef XVisualInfo * (* m_glXChooseVisualProc)(Display *, int, int *); typedef Display * (* m_glXGetCurrentDisplayProc)(); typedef GLXContext (* m_glXGetCurrentContextProc)(); typedef GLXDrawable (* m_glXGetCurrentDrawableProc)(); typedef Bool (* m_glXMakeCurrentProc)(Display *, GLXDrawable, GLXContext); typedef void (* m_glXDestroyContextProc)(Display *, GLXContext); typedef GLXContext (* m_glXCreateContextProc)(Display *, XVisualInfo *, GLXContext, Bool); typedef void (*(* m_glXGetProcAddressProc)(const unsigned char *))(); typedef GLXContext (* m_glXCreateContextAttribsARBProc)(Display *, GLXFBConfig, GLXContext, int, const int *); typedef Display * (* m_XOpenDisplayProc)(const char *); typedef int (* m_XDefaultScreenProc)(Display *); typedef Window (* m_XRootWindowProc)(Display *, int); typedef Colormap (* m_XCreateColormapProc)(Display *, Window, Visual *, int); typedef Window (* m_XCreateWindowProc)(Display *, Window, int, int, unsigned int, unsigned int, unsigned int, int, unsigned int, Visual *, unsigned long, XSetWindowAttributes *); typedef int (* m_XDestroyWindowProc)(Display *, Window); typedef int (* m_XCloseDisplayProc)(Display *); typedef int (* m_XFreeProc)(void *); typedef XErrorHandler (* m_XSetErrorHandlerProc)(XErrorHandler); int SilentXErrorHandler(Display * d, XErrorEvent * e) { return 0; } struct GLContext { PyObject_HEAD void * libgl; void * libx11; Display * dpy; GLXFBConfig * fbc; XVisualInfo * vi; Window wnd; GLXContext ctx; int standalone; int own_window; void * old_context; void * old_display; void * old_window; m_glXChooseFBConfigProc m_glXChooseFBConfig; m_glXChooseVisualProc m_glXChooseVisual; m_glXGetCurrentDisplayProc m_glXGetCurrentDisplay; m_glXGetCurrentContextProc m_glXGetCurrentContext; m_glXGetCurrentDrawableProc m_glXGetCurrentDrawable; m_glXMakeCurrentProc m_glXMakeCurrent; m_glXDestroyContextProc m_glXDestroyContext; m_glXCreateContextProc m_glXCreateContext; m_glXGetProcAddressProc m_glXGetProcAddress; m_glXCreateContextAttribsARBProc m_glXCreateContextAttribsARB; m_XOpenDisplayProc m_XOpenDisplay; m_XDefaultScreenProc m_XDefaultScreen; m_XRootWindowProc m_XRootWindow; m_XCreateColormapProc m_XCreateColormap; m_XCreateWindowProc m_XCreateWindow; m_XDestroyWindowProc m_XDestroyWindow; m_XCloseDisplayProc m_XCloseDisplay; m_XFreeProc m_XFree; m_XSetErrorHandlerProc m_XSetErrorHandler; }; PyTypeObject * GLContext_type; GLContext * meth_create_context(PyObject * self, PyObject * args, PyObject * kwargs) { static char * keywords[] = {"mode", "libgl", "libx11", "glversion", NULL}; const char * mode = "detect"; const char * libgl = "libGL.so"; const char * libx11 = "libX11.so"; int glversion = 330; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|sssi", keywords, &mode, &libgl, &libx11, &glversion)) { return NULL; } GLContext * res = PyObject_New(GLContext, GLContext_type); res->libgl = dlopen(libgl, RTLD_LAZY); if (!res->libgl) { PyErr_Format(PyExc_Exception, "%s not found in /lib, /usr/lib or LD_LIBRARY_PATH", libgl); return NULL; } res->m_glXChooseFBConfig = (m_glXChooseFBConfigProc)dlsym(res->libgl, "glXChooseFBConfig"); if (!res->m_glXChooseFBConfig) { PyErr_Format(PyExc_Exception, "glXChooseFBConfig not found"); return NULL; } res->m_glXChooseVisual = (m_glXChooseVisualProc)dlsym(res->libgl, "glXChooseVisual"); if (!res->m_glXChooseVisual) { PyErr_Format(PyExc_Exception, "glXChooseVisual not found"); return NULL; } res->m_glXGetCurrentDisplay = (m_glXGetCurrentDisplayProc)dlsym(res->libgl, "glXGetCurrentDisplay"); if (!res->m_glXGetCurrentDisplay) { PyErr_Format(PyExc_Exception, "glXGetCurrentDisplay not found"); return NULL; } res->m_glXGetCurrentContext = (m_glXGetCurrentContextProc)dlsym(res->libgl, "glXGetCurrentContext"); if (!res->m_glXGetCurrentContext) { PyErr_Format(PyExc_Exception, "glXGetCurrentContext not found"); return NULL; } res->m_glXGetCurrentDrawable = (m_glXGetCurrentDrawableProc)dlsym(res->libgl, "glXGetCurrentDrawable"); if (!res->m_glXGetCurrentDrawable) { PyErr_Format(PyExc_Exception, "glXGetCurrentDrawable not found"); return NULL; } res->m_glXMakeCurrent = (m_glXMakeCurrentProc)dlsym(res->libgl, "glXMakeCurrent"); if (!res->m_glXMakeCurrent) { PyErr_Format(PyExc_Exception, "glXMakeCurrent not found"); return NULL; } res->m_glXDestroyContext = (m_glXDestroyContextProc)dlsym(res->libgl, "glXDestroyContext"); if (!res->m_glXDestroyContext) { PyErr_Format(PyExc_Exception, "glXDestroyContext not found"); return NULL; } res->m_glXCreateContext = (m_glXCreateContextProc)dlsym(res->libgl, "glXCreateContext"); if (!res->m_glXCreateContext) { PyErr_Format(PyExc_Exception, "glXCreateContext not found"); return NULL; } res->m_glXGetProcAddress = (m_glXGetProcAddressProc)dlsym(res->libgl, "glXGetProcAddress"); if (!res->m_glXGetProcAddress) { PyErr_Format(PyExc_Exception, "glXGetProcAddress not found"); return NULL; } if (strcmp(mode, "detect")) { res->libx11 = dlopen(libx11, RTLD_LAZY); if (!res->libx11) { PyErr_Format(PyExc_Exception, "(detect) %s not loaded", libx11); return NULL; } res->m_XOpenDisplay = (m_XOpenDisplayProc)dlsym(res->libx11, "XOpenDisplay"); if (!res->m_XOpenDisplay) { PyErr_Format(PyExc_Exception, "(detect) XOpenDisplay not found"); return NULL; } res->m_XDefaultScreen = (m_XDefaultScreenProc)dlsym(res->libx11, "XDefaultScreen"); if (!res->m_XDefaultScreen) { PyErr_Format(PyExc_Exception, "(detect) XDefaultScreen not found"); return NULL; } res->m_XRootWindow = (m_XRootWindowProc)dlsym(res->libx11, "XRootWindow"); if (!res->m_XRootWindow) { PyErr_Format(PyExc_Exception, "(detect) XRootWindow not found"); return NULL; } res->m_XCreateColormap = (m_XCreateColormapProc)dlsym(res->libx11, "XCreateColormap"); if (!res->m_XCreateColormap) { PyErr_Format(PyExc_Exception, "(detect) XCreateColormap not found"); return NULL; } res->m_XCreateWindow = (m_XCreateWindowProc)dlsym(res->libx11, "XCreateWindow"); if (!res->m_XCreateWindow) { PyErr_Format(PyExc_Exception, "(detect) XCreateWindow not found"); return NULL; } res->m_XDestroyWindow = (m_XDestroyWindowProc)dlsym(res->libx11, "XDestroyWindow"); if (!res->m_XDestroyWindow) { PyErr_Format(PyExc_Exception, "(detect) XDestroyWindow not found"); return NULL; } res->m_XCloseDisplay = (m_XCloseDisplayProc)dlsym(res->libx11, "XCloseDisplay"); if (!res->m_XCloseDisplay) { PyErr_Format(PyExc_Exception, "(detect) XCloseDisplay not found"); return NULL; } res->m_XFree = (m_XFreeProc)dlsym(res->libx11, "XFree"); if (!res->m_XFree) { PyErr_Format(PyExc_Exception, "(detect) XFree not found"); return NULL; } res->m_XSetErrorHandler = (m_XSetErrorHandlerProc)dlsym(res->libx11, "XSetErrorHandler"); if (!res->m_XSetErrorHandler) { PyErr_Format(PyExc_Exception, "(detect) XSetErrorHandler not found"); return NULL; } } if (!strcmp(mode, "detect")) { res->standalone = false; res->own_window = false; res->ctx = res->m_glXGetCurrentContext(); if (!res->ctx) { PyErr_Format(PyExc_Exception, "(detect) glXGetCurrentContext: cannot detect OpenGL context"); return NULL; } res->wnd = res->m_glXGetCurrentDrawable(); if (!res->wnd) { PyErr_Format(PyExc_Exception, "(detect) glXGetCurrentDrawable failed"); return NULL; } res->dpy = res->m_glXGetCurrentDisplay(); if (!res->dpy) { PyErr_Format(PyExc_Exception, "(detect) glXGetCurrentDisplay failed"); return NULL; } res->fbc = NULL; res->vi = NULL; return res; } if (!strcmp(mode, "share")) { res->standalone = true; res->own_window = false; GLXContext ctx_share = res->m_glXGetCurrentContext(); if (!ctx_share) { PyErr_Format(PyExc_Exception, "(share) glXGetCurrentContext: cannot detect OpenGL context"); return NULL; } res->wnd = res->m_glXGetCurrentDrawable(); if (!res->wnd) { PyErr_Format(PyExc_Exception, "(share) glXGetCurrentDrawable failed"); return NULL; } res->dpy = res->m_glXGetCurrentDisplay(); if (!res->dpy) { PyErr_Format(PyExc_Exception, "(share) glXGetCurrentDisplay failed"); return NULL; } int nelements = 0; res->fbc = res->m_glXChooseFBConfig(res->dpy, res->m_XDefaultScreen(res->dpy), 0, &nelements); if (!res->fbc) { res->m_XCloseDisplay(res->dpy); PyErr_Format(PyExc_Exception, "(share) glXChooseFBConfig failed"); return NULL; } static int attribute_list[] = { GLX_RGBA, GLX_DOUBLEBUFFER, GLX_RED_SIZE, 8, GLX_GREEN_SIZE, 8, GLX_BLUE_SIZE, 8, GLX_DEPTH_SIZE, 24, None, }; res->vi = res->m_glXChooseVisual(res->dpy, res->m_XDefaultScreen(res->dpy), attribute_list); if (!res->vi) { res->m_XCloseDisplay(res->dpy); PyErr_Format(PyExc_Exception, "(share) glXChooseVisual: cannot choose visual"); return NULL; } res->m_XSetErrorHandler(SilentXErrorHandler); if (glversion) { void (* proc)() = res->m_glXGetProcAddress((const unsigned char *)"glXCreateContextAttribsARB"); res->m_glXCreateContextAttribsARB = (m_glXCreateContextAttribsARBProc)proc; if (!res->m_glXCreateContextAttribsARB) { PyErr_Format(PyExc_Exception, "(share) glXCreateContextAttribsARB not found"); return NULL; } int attribs[] = { GLX_CONTEXT_PROFILE_MASK, GLX_CONTEXT_CORE_PROFILE_BIT, GLX_CONTEXT_MAJOR_VERSION, glversion / 100 % 10, GLX_CONTEXT_MINOR_VERSION, glversion / 10 % 10, 0, 0, }; res->ctx = res->m_glXCreateContextAttribsARB(res->dpy, *res->fbc, ctx_share, true, attribs); } else { res->ctx = res->m_glXCreateContext(res->dpy, res->vi, ctx_share, true); } if (!res->ctx) { PyErr_Format(PyExc_Exception, "(share) cannot create context"); return NULL; } res->m_XSetErrorHandler(NULL); if (!res->m_glXMakeCurrent(res->dpy, res->wnd, res->ctx)) { PyErr_Format(PyExc_Exception, "(share) glXMakeCurrent failed"); return NULL; } return res; } if (!strcmp(mode, "standalone")) { res->standalone = true; res->own_window = true; res->dpy = res->m_XOpenDisplay(NULL); if (!res->dpy) { res->dpy = res->m_XOpenDisplay(":0.0"); } if (!res->dpy) { PyErr_Format(PyExc_Exception, "(standalone) XOpenDisplay: cannot open display"); return NULL; } int nelements = 0; res->fbc = res->m_glXChooseFBConfig(res->dpy, res->m_XDefaultScreen(res->dpy), 0, &nelements); if (!res->fbc) { res->m_XCloseDisplay(res->dpy); PyErr_Format(PyExc_Exception, "(standalone) glXChooseFBConfig failed"); return NULL; } static int attribute_list[] = { GLX_RGBA, GLX_DOUBLEBUFFER, GLX_RED_SIZE, 8, GLX_GREEN_SIZE, 8, GLX_BLUE_SIZE, 8, GLX_DEPTH_SIZE, 24, None, }; res->vi = res->m_glXChooseVisual(res->dpy, res->m_XDefaultScreen(res->dpy), attribute_list); if (!res->vi) { res->m_XCloseDisplay(res->dpy); PyErr_Format(PyExc_Exception, "(standalone) glXChooseVisual: cannot choose visual"); return NULL; } XSetWindowAttributes swa; swa.colormap = res->m_XCreateColormap(res->dpy, res->m_XRootWindow(res->dpy, res->vi->screen), res->vi->visual, AllocNone); swa.border_pixel = 0; swa.event_mask = StructureNotifyMask; res->wnd = res->m_XCreateWindow( res->dpy, res->m_XRootWindow(res->dpy, res->vi->screen), 0, 0, 1, 1, 0, res->vi->depth, InputOutput, res->vi->visual, CWBorderPixel | CWColormap | CWEventMask, &swa ); if (!res->wnd) { res->m_XCloseDisplay(res->dpy); PyErr_Format(PyExc_Exception, "(standalone) XCreateWindow: cannot create window"); return NULL; } res->m_XSetErrorHandler(SilentXErrorHandler); if (glversion) { void (* proc)() = res->m_glXGetProcAddress((const unsigned char *)"glXCreateContextAttribsARB"); res->m_glXCreateContextAttribsARB = (m_glXCreateContextAttribsARBProc)proc; if (!res->m_glXCreateContextAttribsARB) { PyErr_Format(PyExc_Exception, "(standalone) glXCreateContextAttribsARB not found"); return NULL; } int attribs[] = { GLX_CONTEXT_PROFILE_MASK, GLX_CONTEXT_CORE_PROFILE_BIT, GLX_CONTEXT_MAJOR_VERSION, glversion / 100 % 10, GLX_CONTEXT_MINOR_VERSION, glversion / 10 % 10, 0, 0, }; res->ctx = res->m_glXCreateContextAttribsARB(res->dpy, *res->fbc, NULL, true, attribs); } else { res->ctx = res->m_glXCreateContext(res->dpy, res->vi, NULL, true); } if (!res->ctx) { PyErr_Format(PyExc_Exception, "(standalone) cannot create context"); return NULL; } res->m_XSetErrorHandler(NULL); if (!res->m_glXMakeCurrent(res->dpy, res->wnd, res->ctx)) { PyErr_Format(PyExc_Exception, "(standalone) glXMakeCurrent failed"); return NULL; } return res; } PyErr_Format(PyExc_Exception, "unknown mode"); return NULL; } PyObject * GLContext_meth_load(GLContext * self, PyObject * arg) { const char * method = PyUnicode_AsUTF8(arg); void * proc = (void *)dlsym(self->libgl, method); if (!proc) { proc = (void *)self->m_glXGetProcAddress((const unsigned char *)method); } return PyLong_FromVoidPtr(proc); } PyObject * GLContext_meth_enter(GLContext * self) { self->old_display = (void *)self->m_glXGetCurrentDisplay(); self->old_window = (void *)self->m_glXGetCurrentDrawable(); self->old_context = (void *)self->m_glXGetCurrentContext(); self->m_glXMakeCurrent(self->dpy, self->wnd, self->ctx); Py_RETURN_NONE; } PyObject * GLContext_meth_exit(GLContext * self) { self->m_glXMakeCurrent((Display *)self->old_display, (Window)self->old_window, (GLXContext)self->old_context); Py_RETURN_NONE; } PyObject * GLContext_meth_release(GLContext * self) { if (self->standalone) { self->m_glXMakeCurrent(self->dpy, None, NULL); self->m_glXDestroyContext(self->dpy, self->ctx); } if (self->own_window) { self->m_XDestroyWindow(self->dpy, self->wnd); self->m_XCloseDisplay(self->dpy); } if (self->fbc) { self->m_XFree(self->fbc); self->fbc = NULL; } if (self->vi) { self->m_XFree(self->vi); self->vi = NULL; } Py_RETURN_NONE; } void GLContext_dealloc(GLContext * self) { Py_TYPE(self)->tp_free(self); } PyMethodDef GLContext_methods[] = { {"load", (PyCFunction)GLContext_meth_load, METH_O, NULL}, {"load_opengl_function", (PyCFunction)GLContext_meth_load, METH_O, NULL}, {"release", (PyCFunction)GLContext_meth_release, METH_NOARGS, NULL}, {"__enter__", (PyCFunction)GLContext_meth_enter, METH_NOARGS, NULL}, {"__exit__", (PyCFunction)GLContext_meth_exit, METH_VARARGS, NULL}, {}, }; PyMemberDef GLContext_members[] = { {"standalone", T_BOOL, offsetof(GLContext, standalone), READONLY, NULL}, {}, }; PyType_Slot GLContext_slots[] = { {Py_tp_methods, GLContext_methods}, {Py_tp_members, GLContext_members}, {Py_tp_dealloc, (void *)GLContext_dealloc}, {}, }; PyType_Spec GLContext_spec = {"x11.GLContext", sizeof(GLContext), 0, Py_TPFLAGS_DEFAULT, GLContext_slots}; PyMethodDef module_methods[] = { {"create_context", (PyCFunction)meth_create_context, METH_VARARGS | METH_KEYWORDS, NULL}, {}, }; PyModuleDef module_def = {PyModuleDef_HEAD_INIT, "x11", NULL, -1, module_methods}; extern "C" PyObject * PyInit_x11() { PyObject * module = PyModule_Create(&module_def); GLContext_type = (PyTypeObject *)PyType_FromSpec(&GLContext_spec); PyModule_AddObject(module, "GLContext", (PyObject *)GLContext_type); return module; } moderngl-glcontext-1573e57/pyproject.toml000066400000000000000000000001711451244733600205340ustar00rootroot00000000000000[build-system] requires = [ "setuptools >= 40.6.2", "wheel >= 0.30.0", ] build-backend = "setuptools.build_meta" moderngl-glcontext-1573e57/setup.py000066400000000000000000000062551451244733600173430ustar00rootroot00000000000000import platform import sys from setuptools import Extension, setup PLATFORMS = {'windows', 'linux', 'darwin'} target = platform.system().lower() for known in PLATFORMS: if target.startswith(known): target = known if target not in PLATFORMS: target = 'linux' if target == 'darwin': import os if sys.version_info[:2] < (3, 12): from distutils.sysconfig import get_config_var from distutils.version import LooseVersion if 'MACOSX_DEPLOYMENT_TARGET' not in os.environ: current_system = LooseVersion(platform.mac_ver()[0]) python_target = LooseVersion(get_config_var('MACOSX_DEPLOYMENT_TARGET')) if python_target < '10.9' and current_system >= '10.9': os.environ['MACOSX_DEPLOYMENT_TARGET'] = '10.9' wgl = Extension( name='glcontext.wgl', sources=['glcontext/wgl.cpp'], extra_compile_args=['-fpermissive'] if 'GCC' in sys.version else [], libraries=['user32', 'gdi32'], ) x11 = Extension( name='glcontext.x11', sources=['glcontext/x11.cpp'], extra_compile_args=['-fpermissive'], libraries=['dl'], ) egl = Extension( name='glcontext.egl', sources=['glcontext/egl.cpp'], extra_compile_args=['-fpermissive'], libraries=['dl'], ) headless = Extension( name='glcontext.headless', sources=['glcontext/headless.cpp'], libraries=['EGL'], ) if target == 'windows': windowed = Extension( name='glcontext.windowed', sources=['glcontext/windowed.cpp'], libraries=['opengl32'], ) if target == 'linux': windowed = Extension( name='glcontext.windowed', sources=['glcontext/windowed.cpp'], extra_compile_args=['-fpermissive'], libraries=['GL'], ) if target == 'darwin': windowed = Extension( name='glcontext.windowed', sources=['glcontext/windowed.cpp'], extra_compile_args=['-fpermissive', '-Wno-deprecated-declarations'], extra_link_args=['-framework', 'OpenGL', '-Wno-deprecated'], ) darwin = Extension( name='glcontext.darwin', sources=['glcontext/darwin.cpp'], extra_compile_args=['-fpermissive', '-Wno-deprecated-declarations'], extra_link_args=['-framework', 'OpenGL', '-Wno-deprecated'], ) ext_modules = { 'windows': [wgl], 'linux': [x11, egl], 'darwin': [darwin], } setup( name='glcontext', version='2.5.0', description='Portable OpenGL Context', long_description=open('README.md', encoding='utf-8').read(), long_description_content_type='text/markdown', url='https://github.com/moderngl/glcontext', author='Szabolcs Dombi', author_email='cprogrammer1994@gmail.com', license='MIT', platforms=['any'], packages=['glcontext'], ext_modules=ext_modules[target], classifiers=[ 'Development Status :: 5 - Production/Stable', 'License :: OSI Approved :: MIT License', 'Operating System :: OS Independent', 'Topic :: Games/Entertainment', 'Topic :: Multimedia :: Graphics', 'Topic :: Multimedia :: Graphics :: 3D Rendering', 'Topic :: Scientific/Engineering :: Visualization', 'Programming Language :: Python :: 3 :: Only', ], ) moderngl-glcontext-1573e57/test.py000066400000000000000000000007451451244733600171600ustar00rootroot00000000000000import ctypes from glcontext import headless devices = headless.devices() headless.init(device=next(x['device'] for x in devices if 'EGL_MESA_device_software' in x['extensions'])) glGetStringPtr = headless.load_opengl_function('glGetString') glGetString = ctypes.cast(glGetStringPtr, ctypes.CFUNCTYPE(ctypes.c_char_p, ctypes.c_uint32)) print(glGetString(0x1F00).decode()) print(glGetString(0x1F01).decode()) print(glGetString(0x1F02).decode()) print(glGetString(0x1F03).decode()) moderngl-glcontext-1573e57/tests/000077500000000000000000000000001451244733600167635ustar00rootroot00000000000000moderngl-glcontext-1573e57/tests/default_context_test.py000066400000000000000000000035771451244733600236000ustar00rootroot00000000000000import os from unittest import TestCase import psutil import glcontext class ContextTestCase(TestCase): def test_create(self): """Basic context testing""" # Create a standalone context # os.environ['GLCONTEXT_WIN_LIBGL'] = 'moo.dll' # os.environ['GLCONTEXT_LINUX_LIBGL'] = 'ligGL.so.1' # os.environ['GLCONTEXT_GLVERSION'] = '430' backend = glcontext.default_backend() ctx = backend(mode='standalone', glversion=330) # Ensure methods are present self.assertTrue(callable(ctx.load)) self.assertTrue(callable(ctx.release)) self.assertTrue(callable(ctx.__enter__)) self.assertTrue(callable(ctx.__exit__)) # Enter and exit context with ctx: pass # Ensure method loading works ptr = ctx.load('glEnable') self.assertIsInstance(ptr, int) self.assertGreater(ptr, 0) # Load non-existent gl method # NOTE: Disabled for now since x11 returns positive values # for non-existent methods # ptr = ctx.load('bogus') # self.assertIsInstance(ptr, int) # self.assertEqual(ptr, 0) def test_mass_create(self): """Create and destroy a large quantity of contexts. The rss memory usage should not grow more than 5x after allocating 1000 contexts. """ process = psutil.Process(os.getpid()) start_rss = process.memory_info().rss for i in range(1000): ctx = glcontext.default_backend()(mode='standalone', glversion=330) # Ensure we can enter context and load a method as a minimum with ctx: self.assertGreater(ctx.load('glBegin'), 0) ctx.release() end_rss = process.memory_info().rss self.assertTrue(end_rss / start_rss < 5.0) moderngl-glcontext-1573e57/tests/requirements.txt000066400000000000000000000000201451244733600222370ustar00rootroot00000000000000pytest psutil