1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
|
"""Utility module for interacting with GBM to select rendering device
The base code here comes from github bug report #6 in the pyopengl
project, thanks to @abandoned-cocoon for that.
"""
import weakref, ctypes, logging, os, glob
from OpenGL.platform import ctypesloader
from OpenGL import _opaque
log = logging.getLogger(__name__)
gbm = ctypesloader.loadLibrary(ctypes.CDLL,"gbm")
__all__ = ('enumerate_devices','open_device','close_device','gbm')
_DEVICE_HANDLES = {}
GBM_BO_USE_SCANOUT = (1 << 0)
GBM_BO_USE_CURSOR = (1 << 1)
GBM_BO_USE_CURSOR_64X64 = GBM_BO_USE_CURSOR
GBM_BO_USE_RENDERING = (1 << 2)
GBM_BO_USE_WRITE = (1 << 3)
GBM_BO_USE_LINEAR = (1 << 4)
GBMDevice = _opaque.opaque_pointer_cls('GBMDevice')
GBMSurface = _opaque.opaque_pointer_cls('GBMSurface')
gbm.gbm_create_device.restype = GBMDevice
gbm.gbm_surface_create.restype = GBMSurface
def filter_bad_drivers(cards, bad_drivers=('nvidia',)):
"""Lookup the driver for each card to exclude loading nvidia devices"""
# this is pci specific, which I suppose means we're going to fail
# if the GPU isn't on the PCI bus, but we don't seem to have
# another way to match up the card to the driver :(
bad_cards = set()
for link in glob.glob('/dev/dri/by-path/pci-*-card'):
base = os.path.basename(link)
pci_id = base[4:-5]
driver = os.path.basename(os.readlink('/sys/bus/pci/devices/%s/driver'%(pci_id,)))
if driver in bad_drivers:
card = os.path.basename(os.readlink(link))
log.debug("Skipping %s because it uses %s driver",card,driver)
bad_cards.add(card)
filtered = [
card for card in cards
if os.path.basename(card) not in bad_cards
]
# assert len(filtered) == 1, filtered
return filtered
def enumerate_devices():
"""Enumerate the set of gbm renderD* devices on the system
Attempts to filter out any nvidia drivers with filter_bad_drivers
along the way.
"""
import glob
# gbm says card* is the correct entry point...
return filter_bad_drivers(sorted(glob.glob('/dev/dri/card*')))
def open_device(path):
"""Open a particular gbm device
* path -- integer index of devices in sorted enumeration, or
device basename (`renderD128`) or a full path-name
as returned from enumerate_devices
Will raise (at least):
* RuntimeError for invalid indices
* IOError/OSError for device access failures
* RuntimeError if we cannot create the gbm device
Caller is responsible for calling close_device(display) on the
resulting opaque pointer in order to release the open file-handle
and deallocate the gbm_device record.
returns GBMDevice, an opaque pointer
"""
if isinstance(path,int):
try:
devices = enumerate_devices()
path = devices[int]
except IndexError:
raise RuntimeError('Only %s devices available, cannot use 0-index %s'%(len(devices),path))
else:
path = os.path.join('/dev/dri',path) # allow for specifying "renderD128"
log.debug("Final device path: %s", path)
fh = open(path,'w')
dev = gbm.gbm_create_device(fh.fileno())
if dev == 0:
fh.close()
raise RuntimeError('Unable to create rendering device for: %s'%(path))
_DEVICE_HANDLES[dev] = fh
return dev
def close_device(device):
"""Close an opened gbm device"""
gbm.gbm_device_destroy(device)
try:
handle = _DEVICE_HANDLES.pop(device)
handle.close()
except KeyError:
pass
def create_surface(device, width=512, height=512, format=None, flags=GBM_BO_USE_RENDERING):
"""Create a GBM surface to use on the given device
devices -- opaque GBMDevice pointer
width,height -- dimensions
format -- EGL_NATIVE_VISUAL_ID from an EGL configuration
flags -- surface flags regarding reading/writing pattern that
is expected for the buffer
returns GBMSurface opaque pointer
"""
if not format:
raise ValueError(
'Use eglGetConfigAttrib(display,config,EGL_NATIVE_VISUAL_ID) to get the native surface format',
)
return gbm.gbm_surface_create(device, width, height, format, flags)
|