GithubHelp home page GithubHelp logo

pegl's Introduction

Pegl: Python 3 binding for EGL

Pegl is a binding to EGL, written in native Python 3 through the ctypes library. It provides comprehensive access to EGL functions, while offering a Pythonic API.

EGL is a specification from the Khronos Group that provides an intermediate layer between other Khronos specifications (OpenGL, OpenGL ES, OpenVG), called “client APIs”, and the native graphics system. EGL can supply an implicit rendering context for each of the client APIs, as well as features like surfaces and buffering.

Pegl wraps EGL version 1.5, and is backwards compatible with previous versions of the specification.

The current Pegl version is 0.2a1. As an alpha version, care should be taken before making use of the library! Please test it out and open a GitHub issue to report the results.

License

Pegl is free software, released under the GNU GPLv3. See the file COPYING and individual source files for the full license terms.

Use

A typical use case might feature these steps:

  1. Create a Display instance
  2. Get a Config instance to match your requirements
  3. Bind the client API you want to use
  4. Get a Context instance and/or a Surface instance, as necessary
  5. Do your work in the client API
  6. Repeat from step 3 to mix different client APIs in the one application

Sample code for steps 1 to 4 might look like this:

>>> import pegl
>>> dpy = pegl.Display()
>>> conf = dpy.choose_config({pegl.ConfigAttrib.RENDERABLE_TYPE:
...                           pegl.ClientAPIFlag.OPENGL_ES})[0]
>>> pegl.bind_api(pegl.ClientAPI.OPENGL_ES)
>>> ctx = conf.create_context()
>>> surf = conf.create_pbuffer_surface({pegl.SurfaceAttrib.WIDTH: 640,
...                                     pegl.SurfaceAttrib.HEIGHT: 480})
>>> ctx.make_current(draw=surf)

Development and testing

Pegl uses tox to run tests and compile coverage data. Tests are currently set up for Python versions 3.7 through 3.9.

I test Pegl on Linux (Fedora with current Mesa releases) and on Windows (Windows 10 with current ANGLE releases). Please run tests on other platforms and open an issue to report your results!

The PEGLEGLVERSION environment variable

By default, Pegl will attempt to load all EGL functions up to version 1.5. If any of a given version’s functions cannot be loaded from the native library, it infers that the library does not support that version and stops there.

It is possible to force Pegl to stop early by setting the PEGLEGLVERSION environment variable. For instance, setting it to 1.4 will cause Pegl to not attempt loading EGL 1.5 functions, even if the library supports them.

This is used in the tests to check backwards compatibility, albeit imperfectly.

Roadmap

0.x series

Releases in this series will provide a wrapper that is Pythonic, but still fairly low-level, and the API is not guaranteed to be stable.

1.x series

Once the basic Pegl functionality is tested and considered usable, I will aim to improve the API, so that an EGL environment can be set up with a minimum of code. When I’m happy with the results, version numbers will be bumped up to 1.x, with a corresponding assurance of API stability.

pegl's People

Contributors

perey avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

pegl's Issues

Publish documentation

The current docs are in pretty good shape, if I do say so myself. They should be published online with some FOSS-friendly provider like Read the Docs.

Automate releases

Bumping version numbers and publishing to PyPI should be automated, or at least streamlined.

Exception in Display destructor

The following exception comes up during testing:

Exception ignored in: <function Display.__del__ at 0x...>
Traceback (most recent call last):
  File "C:\Users\Tim\Documents\Programming\pegl\src\pegl\display.py", line 99, in __del__
    if self._as_parameter_ is egl.EGL_NO_DISPLAY:
AttributeError: 'Display' object has no attribute '_as_parameter_'

As I recall, 846da10 was an attempt to fix this… or else it fixed some other destructor-triggered exception and left this one instead.

More robust EGL library loading on a range of platforms

Installed pegl from source. Seems that libEGL.dll is expected to be put under pegl/egl/common/lib. Windows 10 supplies libEGL.dll under C:\WINDOWS\system32\libEGL.dll as declared by ctypes.util.find_library("libEGL"). Maybe first check find_library first and then try the pegl/egl/common/lib directory?

Work with current aenum version

Pegl uses aenum for its extensible enums, which are used to support different EGL versions and extensions that add new values to existing enumerations.

Code and tests were generally written for aenum 2.2.6, but Pegl is no longer pinned to this version as of d3c6eff. That commit also fixed one resulting bug, but another issue has arisen and others may yet arise.

Current aenum versions (namely 3.1.8) will no longer accept unknown values when constructing an IntFlag instance from an int. Trying to do so doesn't give an error, but returns the int itself. I don't know if this is an intended behaviour change or not.

Before:

>>> class TestFlag(aenum.IntFlag):
...     NONE = 0
...     BIT_0 = 1
...     BIT_1 = 2
...
>>> TestFlag(3)
<TestFlag.BIT_1|BIT_0: 3>
>>> TestFlag(8)
<TestFlag.8: 8>
>>> TestFlag(10)
<TestFlag.8|BIT_1: 10>

After:

>>> class TestFlag(aenum.IntFlag):
...     NONE = 0
...     BIT_0 = 1
...     BIT_1 = 2
...
>>> TestFlag(3)
<TestFlag.BIT_0|BIT_1: 3>
>>> TestFlag(8)
8
>>> TestFlag(10)
10

The difference currently causes problems in tests that load an EGL version lower than the native library actually supports. As a result, enums like ClientAPIFlag aren't extended with newer options... but the library can still use them in values that it returns. This causes tests to fail when they expect a value to be an instance of the enum, but they receive a plain int.

Options:

  1. Be prepared to deal with a plain int. This would affect both tests and user code, and probably means giving up some advantages of enums (like "in" testing for flags).
  2. Add all known flags to all enums regardless of which version is actually loaded. This won't solve the problem for unknown extensions, though.
  3. Define placeholder flags for unused bits on flag enums. Later EGL versions and extensions then add aliases for them.
  4. Report an issue on aenum and hope its behaviour will change back.
  5. Stop depending on aenum and make my own extensible enums.

Of these, option 3 seems like the most practical.

pegl doesn't provide the OpenGL API

(First of all, I must tell I don't understand much about EGL)

So I want to make some OpenGL (computing with shaders) on a headless server. I already have the OpenGL code and it works fine inside PyGame and wxPython. I wanted to "port" it to EGL as I understand this is the only way to make it run without an actual window. I downloaded your code, took the ANGLE dll (libEGL.dll, libGLESv2.dll) in the egl/lib directory and ran your code. It works fine apparently until the point where I want to actually run some OpenGL commands. So here's the program (I've taken part from yours) :

from OpenGL.GL import glClear, GL_COLOR_BUFFER_BIT
import pegl

import pegl, platform
print('Python', platform.python_version(), 'on', platform.platform(terse=True))
dpy = pegl.Display()
print('EGL version:', dpy.version_string, 'by', dpy.vendor)
all_configs = dpy.get_configs()
print('Configs available:', len(all_configs))
if len(all_configs) > 0:
    cfg = all_configs[0]
    print('The first config...')
    print('\tAPIs supported:', cfg.renderable_type)
    print(f'\tColor buffer: {cfg.buffer_size}-bit', cfg.color_buffer_type.name)
else:
    print('What kind of EGL implementation offers no configurations, anyway?!')


conf = dpy.choose_config({pegl.ConfigAttrib.RENDERABLE_TYPE:
                            pegl.ClientAPIFlag.OPENGL_ES})[0]
pegl.bind_api(pegl.ClientAPI.OPENGL_ES)
ctx = conf.create_context()
print(ctx)
surf = conf.create_pbuffer_surface({pegl.SurfaceAttrib.WIDTH: 640,
                                    pegl.SurfaceAttrib.HEIGHT: 480})
print(surf)
print(ctx.make_current(draw=surf))
glClear(GL_COLOR_BUFFER_BIT)

And here is it the output:

Python 3.9.13 on Windows-10
EGL version: 1.5 (ANGLE 2.1.19724 git hash: ceec659ac60b) by Google Inc. (NVIDIA)
Configs available: 200
The first config...
        APIs supported: ClientAPIFlag.OPENGL_ES3|OPENGL_ES2|OPENGL_ES
        Color buffer: 16-bit RGB
Google Inc. (NVIDIA)
(1, 5, '(ANGLE 2.1.19724 git hash: ceec659ac60b)')
<pegl.context.Context object at 0x000001D939DD67F0>
<pegl.surface.Surface object at 0x000001D93A60F520>
None
Traceback (most recent call last):
  File "d:\newgit\HECEPython\debug\test_glsim\test_pegl.py", line 31, in <module>
    glClear(GL_COLOR_BUFFER_BIT)
  File "C:\Users\StephaneC\AppData\Local\Programs\Python\Python39\lib\site-packages\OpenGL\platform\baseplatform.py", line 415, in __call__
    return self( *args, **named )
  File "C:\Users\StephaneC\AppData\Local\Programs\Python\Python39\lib\site-packages\OpenGL\error.py", 
line 230, in glCheckError
    raise self._errorClass(
OpenGL.error.GLError: GLError(
        err = 1282,
        description = b'op\xe9ration non valide',
        baseOperation = glClear,
        cArguments = (GL_COLOR_BUFFER_BIT,)
)

The first obvious point is that it crashes on a simple OpenGL code. Did I miss something ? The second point is that the reported supported API's don't include regular OpenGL. That's surprising. Just to be on the safe side I also included opengl32.dll in the egl/lib directory but to no avail...

So it doesn't work but I'm not sure it is on the pegl side or mine :-( So if you ever have some interest in this issue, I'd be happy to hear it :-)

Easier way to specify attributes

Specifying attributes (for Config, Context, Display, Image, Surface, and Sync objects) is currently pretty verbose, e.g.

cfg.create_pbuffer_surface({SurfaceAttrib.GL_COLORSPACE: GLColorspace.SRGB,
                            SurfaceAttrib.WIDTH: 256,
                            SurfaceAttrib.HEIGHT: 256,
                            SurfaceAttrib.LARGEST_PBUFFER: True})

It should be possible for Pegl to identify the relevant enums and build the attribs dict itself, given just the names. The above example might be rewritten like so:

cfg.create_pbuffer_surface({'GL_COLORSPACE': 'SRGB', 'WIDTH': 256,
                            'HEIGHT': 256, 'LARGEST_PBUFFER': True})

Other things to consider are:

  • Keep the names as ALL_CAPS? Or accept them in lower_case, which is more consistent with instance properties?
  • Keep everything in a dict? Or take keyword arguments?

Using keyword arguments, the example might instead look like this:

cfg.create_pbuffer_surface(gl_colorspace='SRGB', width=256, height=256,
                           largest_pbuffer=True)

Set up automated testing

The refreshed Pegl has a lot more tests in a tox setup. It should be possible to take advantage of Github Actions (and/or other FOSS-friendly providers) to run these automatically.

Pegl has no attribute display

After installing pegl via:

pip install pegl

I get following error when trying to create the egl context:

import pegl
from pegl.attribs.config import ClientAPIs, CBufferTypes
from pegl.attribs.context import ContextAPIs
dpy = pegl.display.Display()

AttributeError: module 'pegl' has no attribute 'display'

Test on Python 3.10

Python 3.10 has been out for six months now. I should probably start testing against it sooner rather than later, especially since 3.11 is scheduled to enter beta soon!

Fix exception in surface and context destructors

Just tried running the sample code under Pegl 0.2a1 on Raspberry Pi OS. All went well until cleanup time:

>>> import pegl
...
>>> ctx.make_current(draw=surf)
>>> exit()
Exception ignored in: <function Context.__del__ at 0xb611eb20>
Traceback (most recent call last):
  File "/home/pi/pegl-test/lib/python3.9/site-packages/pegl/context.py", line 69, in __del__
  File "/home/pi/pegl-test/lib/python3.9/site-packages/pegl/egl/_common.py", line 210, in error_check
pegl.errors.NotInitializedError: 
Exception ignored in: <function Surface.__del__ at 0xb612d148>
Traceback (most recent call last):
  File "/home/pi/pegl-test/lib/python3.9/site-packages/pegl/surface.py", line 51, in __del__
  File "/home/pi/pegl-test/lib/python3.9/site-packages/pegl/egl/_common.py", line 210, in error_check
pegl.errors.NotInitializedError: 

Not only did two (ignored) exceptions get raised, they’re both singularly uninformative, with an apparently empty error text. I need to (a) make sure there’s a meaningful message (or else none at all?), and (b) stop it happening.

Native library import does not support linux3

Shouldn't line 46 in native.py be set to
if sys.platform == 'linux': or if sys.platfom == 'linux2' or sys.platform == 'linux3'?
That should enable usage of pegl on modern kernels.
Or, maybe, there is no support for 3rd kernel?
Thank you in advance.

Cant run minimal example

Hi,

Thanks for this code! Unfortunately I am not able to run the minimal example in the README. I get the following error. Any idea?
I have some pyopengl code which is using glfw at the moment but I would like to use pegl to use in a headless server.

conf = dpy.choose_config({pegl.ConfigAttrib.RENDERABLE_TYPE: pegl.ClientAPIFlag.OPENGL_ES})[0]
IndexError: tuple index out of range

pegl version format

Currently with the format w.x_y.z pip does not recognise the version format. Running pip install pegl gives ERROR: Could not find a version that satisfies the requirement pegl (from versions: 0.1a3~1.4, 0.1a4_1.4) whereas downloading the sdist gives WARNING: Built wheel for pegl is invalid: Metadata 1.2 mandates PEP 440 version, but '0.1a4-1.4' is not. It does install, however it uses the outdated python setup.py install mechanism. Using a PEP 440 version string could fix this, however I don't see how you would be able to include both the wrapped EGL version and the python PEGL version in one version string.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.