1"""Cython memoryview implementation of buffer-api format handler""" 2from ctypes import c_void_p 3from OpenGL_accelerate.formathandler cimport FormatHandler 4import traceback, weakref 5from OpenGL.error import CopyError 6from OpenGL._bytes import bytes,unicode 7 8# Following is from the old python_buffer.pxd 9cdef extern from "Python.h": 10 11 cdef enum: 12 PyBUF_SIMPLE, 13 PyBUF_WRITABLE, 14 PyBUF_WRITEABLE, # backwards compatability 15 PyBUF_FORMAT, 16 PyBUF_ND, 17 PyBUF_STRIDES, 18 PyBUF_C_CONTIGUOUS, 19 PyBUF_F_CONTIGUOUS, 20 PyBUF_ANY_CONTIGUOUS, 21 PyBUF_INDIRECT, 22 PyBUF_CONTIG, 23 PyBUF_CONTIG_RO, 24 PyBUF_STRIDED, 25 PyBUF_STRIDED_RO, 26 PyBUF_RECORDS, 27 PyBUF_RECORDS_RO, 28 PyBUF_FULL, 29 PyBUF_FULL_RO, 30 PyBUF_READ, 31 PyBUF_WRITE, 32 PyBUF_SHADOW 33 34 bint PyObject_CheckBuffer(object obj) 35 36 int PyObject_GetBuffer(object obj, Py_buffer *view, int flags) except -1 37 void PyBuffer_Release(object obj, object view) 38 void* PyBuffer_GetPointer(Py_buffer *view, Py_ssize_t *indices) 39 int PyObject_CopyToObject(object obj, void *buf, Py_ssize_t len, char fortran) except -1 40 bint PyBuffer_IsContiguous(Py_buffer *view, char fort) 41 42 object PyMemoryView_FromObject(object obj) 43 object PyMemoryView_FromBuffer(Py_buffer *view) 44 45 object PyMemoryView_GetContiguous(object obj, int buffertype, char order) 46 47 bint PyMemoryView_Check(object obj) 48 Py_buffer *PyMemoryView_GET_BUFFER(object obj) 49 50cdef class MemoryviewHandler(FormatHandler): 51 cdef public dict array_to_gl_constant 52 cdef public dict gl_constant_to_array 53 isOutput = True 54 55 def __init__( self, ERROR_ON_COPY=None, a_to_gl=None ): 56 if ERROR_ON_COPY is None: 57 from OpenGL import _configflags 58 ERROR_ON_COPY = _configflags.ERROR_ON_COPY 59 if a_to_gl is None: 60 try: 61 from OpenGL.arrays._arrayconstants import ARRAY_TO_GL_TYPE_MAPPING 62 except ImportError as err: 63 raise RuntimeError( "Unable to load array constants" ) 64 a_to_gl = ARRAY_TO_GL_TYPE_MAPPING 65 self.ERROR_ON_COPY = ERROR_ON_COPY 66 self.array_to_gl_constant = a_to_gl 67 68 cdef object c_as_memoryview( self, object instance ): 69 """Ensure instance is a memory view instance or make it one""" 70 if not PyMemoryView_Check( instance ): 71 # TODO: respect no-copy flag! 72 instance = PyMemoryView_GetContiguous( 73 instance, 74 PyBUF_STRIDES|PyBUF_FORMAT|PyBUF_C_CONTIGUOUS, 75 'C' 76 ) 77 return instance 78 cdef c_from_param( self, object instance, object typeCode ): 79 """simple function-based from_param""" 80 if not PyMemoryView_Check( instance ): 81 raise TypeError( '''Need a MemoryView instance in from_param (call asArray first)''' ) 82 return c_void_p( self.c_dataPointer( instance ) ) 83 cdef c_dataPointer( self, object instance ): 84 """Retrieve data-pointer directly""" 85 return <size_t> PyMemoryView_GET_BUFFER( self.c_as_memoryview( instance )).buf 86 cdef c_zeros( self, object dims, object typeCode ): 87 """Create an array initialized to zeros""" 88 raise NotImplementedError( "Need to use a subclass to get zeros support" ) 89 cdef c_arraySize( self, object instance, object typeCode ): 90 """Retrieve array size reference""" 91 cdef Py_buffer * buffer 92 buffer = PyMemoryView_GET_BUFFER( self.c_as_memoryview( instance ) ) 93 return buffer.len//buffer.itemsize 94 cdef c_arrayByteCount( self, object instance ): 95 """Given a data-value, calculate number of bytes required to represent""" 96 return PyMemoryView_GET_BUFFER( self.c_as_memoryview( instance ) ).len 97 98 cdef c_arrayToGLType( self, object instance ): 99 """Given a value, guess OpenGL type of the corresponding pointer""" 100 cdef Py_buffer * buffer 101 buffer = PyMemoryView_GET_BUFFER( self.c_as_memoryview( instance ) ) 102 cdef object constant = self.array_to_gl_constant.get( buffer.format ) 103 if constant is None: 104 if isinstance(buffer.format,bytes): 105 constant = self.array_to_gl_constant.get(buffer.format.decode('utf-8')) 106 if constant is None: 107 raise TypeError( 108 """Don't know GL type for array of type %r, known types: %s\nvalue:%s"""%( 109 buffer.format, self.array_to_gl_constant.keys(), buffer.format, 110 ) 111 ) 112 return constant 113 114 cdef c_asArray( self, object instance, object typeCode ): 115 """Retrieve the given value as a (contiguous) array of type typeCode""" 116 return self.c_as_memoryview( instance ) 117# cdef Py_buffer * buffer 118# cdef object result 119# result = self.c_as_memoryview( instance ) 120# buffer = PyMemoryView_GET_BUFFER( result ) 121# actual_type = self.array_to_gl_constant.get( buffer.format, self.array_to_gl_constant ) 122# if actual_type != typeCode: 123# raise TypeError( 'Incompatible type: %s, needed %s', buffer.format, typeCode ) 124# return result 125 cdef c_unitSize( self, object instance, typeCode ): 126 """Retrieve last dimension of the array""" 127 cdef Py_buffer * buffer 128 view = self.c_as_memoryview( instance ) 129 buffer = PyMemoryView_GET_BUFFER( view ) 130 return buffer.shape[buffer.ndim-1] 131 cdef c_dimensions( self, object instance ): 132 """Retrieve full set of dimensions for the array as tuple""" 133 cdef Py_buffer * buffer 134 buffer = PyMemoryView_GET_BUFFER( self.c_as_memoryview( instance ) ) 135 cdef dim = 0 136 cdef list result 137 result = [] 138 for dim in range(buffer.ndim): 139 result.append( buffer.shape[dim] ) 140 return result 141