PyOpenGL-accelerate 3.1.10__tar.gz → 4.0.0a4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. {pyopengl_accelerate-3.1.10 → pyopengl_accelerate-4.0.0a4}/OpenGL_accelerate/__init__.py +2 -2
  2. pyopengl_accelerate-4.0.0a4/PKG-INFO +46 -0
  3. pyopengl_accelerate-4.0.0a4/PyOpenGL_accelerate.egg-info/PKG-INFO +46 -0
  4. {pyopengl_accelerate-3.1.10 → pyopengl_accelerate-4.0.0a4}/PyOpenGL_accelerate.egg-info/SOURCES.txt +13 -0
  5. pyopengl_accelerate-4.0.0a4/PyOpenGL_accelerate.egg-info/requires.txt +1 -0
  6. pyopengl_accelerate-4.0.0a4/pyproject.toml +72 -0
  7. pyopengl_accelerate-4.0.0a4/setup.py +224 -0
  8. {pyopengl_accelerate-3.1.10 → pyopengl_accelerate-4.0.0a4}/src/arraydatatype.pyx +113 -3
  9. pyopengl_accelerate-4.0.0a4/src/c/generated/pygl_EGL.c +6283 -0
  10. pyopengl_accelerate-4.0.0a4/src/c/generated/pygl_GL.c +120234 -0
  11. pyopengl_accelerate-4.0.0a4/src/c/generated/pygl_GLES1.c +15983 -0
  12. pyopengl_accelerate-4.0.0a4/src/c/generated/pygl_GLES2.c +29952 -0
  13. pyopengl_accelerate-4.0.0a4/src/c/generated/pygl_GLES3.c +7004 -0
  14. pyopengl_accelerate-4.0.0a4/src/c/generated/pygl_GLSC2.c +4350 -0
  15. pyopengl_accelerate-4.0.0a4/src/c/generated/pygl_GLX.c +5068 -0
  16. pyopengl_accelerate-4.0.0a4/src/c/generated/pygl_WGL.c +5736 -0
  17. pyopengl_accelerate-4.0.0a4/src/c/generated/pygl_generated.c +44 -0
  18. pyopengl_accelerate-4.0.0a4/src/c/generated/pygl_modules.c +23632 -0
  19. pyopengl_accelerate-4.0.0a4/src/c/pygl_handwritten.c +119 -0
  20. pyopengl_accelerate-4.0.0a4/src/c/pygl_runtime.c +2966 -0
  21. {pyopengl_accelerate-3.1.10 → pyopengl_accelerate-4.0.0a4}/src/errorchecker.pyx +52 -9
  22. {pyopengl_accelerate-3.1.10 → pyopengl_accelerate-4.0.0a4}/src/wrapper.pyx +11 -0
  23. {pyopengl_accelerate-3.1.10 → pyopengl_accelerate-4.0.0a4}/tests/test_arraydatatypeaccel.py +19 -4
  24. {pyopengl_accelerate-3.1.10 → pyopengl_accelerate-4.0.0a4}/tests/test_numpyaccel.py +21 -2
  25. pyopengl_accelerate-3.1.10/PKG-INFO +0 -83
  26. pyopengl_accelerate-3.1.10/PyOpenGL_accelerate.egg-info/PKG-INFO +0 -83
  27. pyopengl_accelerate-3.1.10/pyproject.toml +0 -49
  28. pyopengl_accelerate-3.1.10/setup.py +0 -121
  29. {pyopengl_accelerate-3.1.10 → pyopengl_accelerate-4.0.0a4}/MANIFEST.in +0 -0
  30. {pyopengl_accelerate-3.1.10 → pyopengl_accelerate-4.0.0a4}/OpenGL_accelerate/formathandler.pxd +0 -0
  31. {pyopengl_accelerate-3.1.10 → pyopengl_accelerate-4.0.0a4}/OpenGL_accelerate/wrapper.pxd +0 -0
  32. {pyopengl_accelerate-3.1.10 → pyopengl_accelerate-4.0.0a4}/PyOpenGL_accelerate.egg-info/dependency_links.txt +0 -0
  33. {pyopengl_accelerate-3.1.10 → pyopengl_accelerate-4.0.0a4}/PyOpenGL_accelerate.egg-info/top_level.txt +0 -0
  34. {pyopengl_accelerate-3.1.10 → pyopengl_accelerate-4.0.0a4}/README.md +0 -0
  35. {pyopengl_accelerate-3.1.10 → pyopengl_accelerate-4.0.0a4}/license.txt +0 -0
  36. {pyopengl_accelerate-3.1.10 → pyopengl_accelerate-4.0.0a4}/setup.cfg +0 -0
  37. {pyopengl_accelerate-3.1.10 → pyopengl_accelerate-4.0.0a4}/src/buffers_formathandler.pyx +0 -0
  38. {pyopengl_accelerate-3.1.10 → pyopengl_accelerate-4.0.0a4}/src/formathandler.pyx +0 -0
  39. {pyopengl_accelerate-3.1.10 → pyopengl_accelerate-4.0.0a4}/src/latebind.pyx +0 -0
  40. {pyopengl_accelerate-3.1.10 → pyopengl_accelerate-4.0.0a4}/src/nones_formathandler.pyx +0 -0
  41. {pyopengl_accelerate-3.1.10 → pyopengl_accelerate-4.0.0a4}/src/numpy_formathandler.pyx +0 -0
  42. {pyopengl_accelerate-3.1.10 → pyopengl_accelerate-4.0.0a4}/src/vbo.pyx +0 -0
@@ -7,5 +7,5 @@ PyOpenGL package and is built via the setupaccel.py
7
7
  script in the top level of the PyOpenGL source package.
8
8
  """
9
9
 
10
- __version__ = "3.1.10"
11
- __version_tuple__ = (3, 1, 10)
10
+ __version__ = "4.0.0a4"
11
+ __version_tuple__ = (4, 0, 0)
@@ -0,0 +1,46 @@
1
+ Metadata-Version: 2.4
2
+ Name: PyOpenGL-accelerate
3
+ Version: 4.0.0a4
4
+ Summary: Cython-coded accelerators for PyOpenGL
5
+ Home-page: http://pyopengl.sourceforge.net
6
+ Download-URL: http://sourceforge.net/project/showfiles.php?group_id=5988
7
+ Author: Mike C. Fletcher
8
+ Author-email: "Mike C. Fletcher" <mcfletch@vrplumber.com>
9
+ License-Expression: BSD-3-Clause
10
+ Project-URL: Homepage, https://mcfletch.github.io/pyopengl/
11
+ Project-URL: Download, https://pypi.org/project/PyOpenGL-accelerate/
12
+ Project-URL: Source, https://github.com/mcfletch/pyopengl
13
+ Project-URL: Documentation, https://mcfletch.github.io/pyopengl/documentation/index.html
14
+ Keywords: Graphics,3D,OpenGL,GLU,GLUT,GLE,GLX,EXT,ARB,Mesa,PyOpenGL
15
+ Platform: Win32
16
+ Platform: Linux
17
+ Platform: OS-X
18
+ Platform: Posix
19
+ Classifier: Programming Language :: Python
20
+ Classifier: Programming Language :: Python :: 3
21
+ Classifier: Topic :: Multimedia :: Graphics :: 3D Rendering
22
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
23
+ Classifier: Intended Audience :: Developers
24
+ Requires-Python: >=3.9
25
+ Description-Content-Type: text/markdown
26
+ License-File: license.txt
27
+ Requires-Dist: PyOpenGL==4.0.0a4
28
+ Dynamic: download-url
29
+ Dynamic: license-file
30
+ Dynamic: requires-dist
31
+
32
+ # Acceleration code for PyOpenGL
33
+
34
+ This set of C (Cython) extensions provides acceleration of common operations
35
+ for slow points in PyOpenGL 3.x. It is not a requirement for using PyOpenGL
36
+ but performance without it will be poor.
37
+
38
+ ## Build Process
39
+
40
+ Cython is updated frequently to support newer versions of Python. As of
41
+ release 3.1.9 we no longer check in the Cython generated code for the
42
+ wrapper modules, relying on the build machines to generate the wrappers.
43
+
44
+ The Github CI Pipeline should generate and release binary builds for most
45
+ major platforms (Windows, Linux, Mac), but if you need to build from source,
46
+ a `pip install .` **should** work from the PyOpenGL repository.
@@ -0,0 +1,46 @@
1
+ Metadata-Version: 2.4
2
+ Name: PyOpenGL-accelerate
3
+ Version: 4.0.0a4
4
+ Summary: Cython-coded accelerators for PyOpenGL
5
+ Home-page: http://pyopengl.sourceforge.net
6
+ Download-URL: http://sourceforge.net/project/showfiles.php?group_id=5988
7
+ Author: Mike C. Fletcher
8
+ Author-email: "Mike C. Fletcher" <mcfletch@vrplumber.com>
9
+ License-Expression: BSD-3-Clause
10
+ Project-URL: Homepage, https://mcfletch.github.io/pyopengl/
11
+ Project-URL: Download, https://pypi.org/project/PyOpenGL-accelerate/
12
+ Project-URL: Source, https://github.com/mcfletch/pyopengl
13
+ Project-URL: Documentation, https://mcfletch.github.io/pyopengl/documentation/index.html
14
+ Keywords: Graphics,3D,OpenGL,GLU,GLUT,GLE,GLX,EXT,ARB,Mesa,PyOpenGL
15
+ Platform: Win32
16
+ Platform: Linux
17
+ Platform: OS-X
18
+ Platform: Posix
19
+ Classifier: Programming Language :: Python
20
+ Classifier: Programming Language :: Python :: 3
21
+ Classifier: Topic :: Multimedia :: Graphics :: 3D Rendering
22
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
23
+ Classifier: Intended Audience :: Developers
24
+ Requires-Python: >=3.9
25
+ Description-Content-Type: text/markdown
26
+ License-File: license.txt
27
+ Requires-Dist: PyOpenGL==4.0.0a4
28
+ Dynamic: download-url
29
+ Dynamic: license-file
30
+ Dynamic: requires-dist
31
+
32
+ # Acceleration code for PyOpenGL
33
+
34
+ This set of C (Cython) extensions provides acceleration of common operations
35
+ for slow points in PyOpenGL 3.x. It is not a requirement for using PyOpenGL
36
+ but performance without it will be poor.
37
+
38
+ ## Build Process
39
+
40
+ Cython is updated frequently to support newer versions of Python. As of
41
+ release 3.1.9 we no longer check in the Cython generated code for the
42
+ wrapper modules, relying on the build machines to generate the wrappers.
43
+
44
+ The Github CI Pipeline should generate and release binary builds for most
45
+ major platforms (Windows, Linux, Mac), but if you need to build from source,
46
+ a `pip install .` **should** work from the PyOpenGL repository.
@@ -10,6 +10,7 @@ OpenGL_accelerate/wrapper.pxd
10
10
  PyOpenGL_accelerate.egg-info/PKG-INFO
11
11
  PyOpenGL_accelerate.egg-info/SOURCES.txt
12
12
  PyOpenGL_accelerate.egg-info/dependency_links.txt
13
+ PyOpenGL_accelerate.egg-info/requires.txt
13
14
  PyOpenGL_accelerate.egg-info/top_level.txt
14
15
  src/arraydatatype.pyx
15
16
  src/buffers_formathandler.pyx
@@ -20,5 +21,17 @@ src/nones_formathandler.pyx
20
21
  src/numpy_formathandler.pyx
21
22
  src/vbo.pyx
22
23
  src/wrapper.pyx
24
+ src/c/pygl_handwritten.c
25
+ src/c/pygl_runtime.c
26
+ src/c/generated/pygl_EGL.c
27
+ src/c/generated/pygl_GL.c
28
+ src/c/generated/pygl_GLES1.c
29
+ src/c/generated/pygl_GLES2.c
30
+ src/c/generated/pygl_GLES3.c
31
+ src/c/generated/pygl_GLSC2.c
32
+ src/c/generated/pygl_GLX.c
33
+ src/c/generated/pygl_WGL.c
34
+ src/c/generated/pygl_generated.c
35
+ src/c/generated/pygl_modules.c
23
36
  tests/test_arraydatatypeaccel.py
24
37
  tests/test_numpyaccel.py
@@ -0,0 +1 @@
1
+ PyOpenGL==4.0.0a4
@@ -0,0 +1,72 @@
1
+ [project]
2
+ name="PyOpenGL-accelerate"
3
+ dynamic=["version", "dependencies"]
4
+ description = "Cython-coded accelerators for PyOpenGL"
5
+ authors = [
6
+ {name="Mike C. Fletcher",email="mcfletch@vrplumber.com"},
7
+ ]
8
+ readme = {file="README.md", content-type = "text/markdown"}
9
+ license = "BSD-3-Clause"
10
+ license-files = ["license.txt"]
11
+ requires-python = ">=3.9"
12
+ keywords = [
13
+ "Graphics",
14
+ "3D",
15
+ "OpenGL",
16
+ "GLU",
17
+ "GLUT",
18
+ "GLE",
19
+ "GLX",
20
+ "EXT",
21
+ "ARB",
22
+ "Mesa",
23
+ "PyOpenGL",
24
+ ]
25
+ classifiers = [
26
+ "Programming Language :: Python",
27
+ "Programming Language :: Python :: 3",
28
+ "Topic :: Multimedia :: Graphics :: 3D Rendering",
29
+ "Topic :: Software Development :: Libraries :: Python Modules",
30
+ "Intended Audience :: Developers",
31
+ ]
32
+ [project.urls]
33
+ Homepage = "https://mcfletch.github.io/pyopengl/"
34
+ Download = "https://pypi.org/project/PyOpenGL-accelerate/"
35
+ Source = "https://github.com/mcfletch/pyopengl"
36
+ Documentation = "https://mcfletch.github.io/pyopengl/documentation/index.html"
37
+
38
+ [build-system]
39
+ # numpy 2.0+ produces wheels that are ABI-compatible with numpy >= 1.26 at runtime
40
+ # via the PyDataType_* accessor backports. Mostly hit by cibuildwheel.
41
+ requires = [
42
+ "setuptools >= 77.0",
43
+ "Cython >= 0.28",
44
+ "numpy >= 2.0",
45
+ ]
46
+ build-backend = "setuptools.build_meta"
47
+
48
+ [tool.setuptools.dynamic]
49
+ version = {attr = "OpenGL_accelerate.__version__"}
50
+ # The dependency on PyOpenGL is an exact pin on this package's own version, so
51
+ # setup.py builds it from the one number rather than a second copy living here
52
+ # to drift -- see pyopengl_requirement().
53
+
54
+ [tool.setuptools.packages.find]
55
+ namespaces=false
56
+ include=["OpenGL_accelerate"]
57
+ exclude=["tests","src"]
58
+
59
+ # uv decides whether its cached metadata for a source tree is still current
60
+ # from pyproject.toml, setup.py and setup.cfg alone. This project's version
61
+ # lives in OpenGL_accelerate/__init__.py, so name that file too: without it a
62
+ # version bump leaves uv answering with the previous number, and a dependent
63
+ # requiring the new one resolves against PyPI rather than this checkout.
64
+ [tool.uv]
65
+ # setup.py too: the dependency on PyOpenGL is built there, from the version
66
+ # in OpenGL_accelerate/__init__.py, so both files decide this package's
67
+ # metadata and a change to either has to invalidate the cached answer.
68
+ cache-keys = [
69
+ { file = "pyproject.toml" },
70
+ { file = "setup.py" },
71
+ { file = "OpenGL_accelerate/__init__.py" },
72
+ ]
@@ -0,0 +1,224 @@
1
+ #!/usr/bin/env python
2
+ """Builds accelleration functions for PyOpenGL
3
+ """
4
+ import sys
5
+ from setuptools import setup, Extension
6
+
7
+ try:
8
+ from Cython.Distutils import build_ext
9
+ except ImportError:
10
+ have_cython = False
11
+ build_ext = False
12
+ else:
13
+ have_cython = True
14
+
15
+ import sys, os
16
+
17
+ HERE = os.path.normpath(os.path.abspath(os.path.dirname(__file__)))
18
+
19
+ extensions = []
20
+
21
+
22
+ def _our_version():
23
+ """This package's version, read without importing it.
24
+
25
+ Importing ``OpenGL_accelerate`` during its own build would need the
26
+ extensions that are not built yet, so the assignment is read out of the
27
+ source the way the build backend reads it.
28
+ """
29
+ import re
30
+
31
+ with open(
32
+ os.path.join(HERE, 'OpenGL_accelerate', '__init__.py'), encoding='utf-8'
33
+ ) as handle:
34
+ source = handle.read()
35
+ found = re.search(r'^__version__\s*=\s*["\']([^"\']+)["\']', source, re.M)
36
+ if not found:
37
+ raise RuntimeError('OpenGL_accelerate/__init__.py states no __version__')
38
+ return found.group(1)
39
+
40
+
41
+ def pyopengl_requirement():
42
+ """The PyOpenGL this accelerate pairs with, as a requirement string.
43
+
44
+ Exact, because the two are released together from one repository and the
45
+ dispatch extension's tables are generated from that PyOpenGL: a mismatched
46
+ pair does not degrade, it dispatches through the wrong slot indices.
47
+ ``OpenGL._dispatch`` refuses one at import; this stops pip assembling one
48
+ in the first place, which is a better place to learn it than the first
49
+ entry point a program calls.
50
+
51
+ Read from this package's own version so there is one number to bump.
52
+ """
53
+ return 'PyOpenGL==%s' % (_our_version(),)
54
+
55
+
56
+ def dispatch_extension():
57
+ """The registry-generated C implementation of the OpenGL entry points.
58
+
59
+ It lives here rather than in ``pyopengl`` so that ``pyopengl`` stays a
60
+ single universal wheel: the C is what needs a compiler and a wheel per
61
+ platform, and this package is already the optional compiled companion.
62
+ "Is the fast path available?" is then the question it has always been --
63
+ is accelerate installed?
64
+
65
+ Both packages are released together from one repository, and the two
66
+ share generated tables, so the versions must match exactly; the module
67
+ checks that at import.
68
+ """
69
+ import glob
70
+
71
+ if os.environ.get('PYOPENGL_NO_C_DISPATCH'):
72
+ return []
73
+ if sys.implementation.name != 'cpython':
74
+ # The extension reaches CPython's vectorcall protocol directly. On
75
+ # PyPy it would compile, import, and route every call through an
76
+ # emulated vectorcall across the cpyext boundary -- the slowest path
77
+ # available, chosen by default, on the interpreter the ctypes
78
+ # implementation exists to serve.
79
+ return []
80
+ generated = os.path.join(HERE, 'src', 'c', 'generated')
81
+ sources = sorted(
82
+ os.path.relpath(path, HERE).replace(os.sep, '/')
83
+ for path in glob.glob(os.path.join(generated, '*.c'))
84
+ )
85
+ if not sources:
86
+ return []
87
+ sources.insert(0, 'src/c/pygl_handwritten.c')
88
+ sources.insert(0, 'src/c/pygl_runtime.c')
89
+ # setuptools does not work out header dependencies, so a change to pygl.h
90
+ # would otherwise leave the generated objects stale and the build mixed:
91
+ # objects compiled against one version of a macro linked with a runtime
92
+ # compiled against another.
93
+ headers = [
94
+ 'src/c/pygl.h',
95
+ 'src/c/generated/pygl_elements.h',
96
+ 'src/c/generated/pygl_glgets.h',
97
+ ]
98
+ return [
99
+ Extension(
100
+ 'OpenGL_accelerate.dispatch',
101
+ sources=sources,
102
+ include_dirs=['src/c', 'src/c/generated'],
103
+ # The extension states which PyOpenGL its tables were generated
104
+ # from, so that a mismatched pair is refused with a sentence rather
105
+ # than dispatching through the wrong slot indices. The two are
106
+ # released together and carry the same number, so this is the
107
+ # accelerate version.
108
+ define_macros=[('PYOPENGL_VERSION', '"%s"' % (_our_version(),))],
109
+ depends=[
110
+ path for path in headers if os.path.exists(os.path.join(HERE, path))
111
+ ],
112
+ # Optional so a source install without a compiler still yields a
113
+ # working accelerate; PyOpenGL falls back to ctypes on its own.
114
+ # Set PYOPENGL_REQUIRE_C_DISPATCH=1 while working on it, or a
115
+ # compile error is a warning and the stale object is kept.
116
+ optional=not os.environ.get('PYOPENGL_REQUIRE_C_DISPATCH'),
117
+ )
118
+ ]
119
+
120
+
121
+ extensions.extend(dispatch_extension())
122
+
123
+
124
+ def cython_extension(
125
+ name,
126
+ include_dirs=(),
127
+ ):
128
+ """Create a cython extension object"""
129
+ filenames = "%(name)s.c" % locals(), "%(name)s.pyx" % locals()
130
+ filename = filenames[bool(have_cython)]
131
+ return Extension(
132
+ "OpenGL_accelerate.%(name)s" % locals(),
133
+ [
134
+ os.path.join("src", filename),
135
+ ],
136
+ include_dirs=[
137
+ os.path.join(HERE, "src"),
138
+ HERE,
139
+ ]
140
+ + list(include_dirs),
141
+ define_macros=[
142
+ ('NPY_NO_DEPRECATED_API', 'NPY_1_7_API_VERSION'),
143
+ ],
144
+ compiler_directives={'language_level': "3"} if have_cython else {},
145
+ )
146
+
147
+
148
+ extensions.extend(
149
+ [
150
+ cython_extension("wrapper"),
151
+ cython_extension("formathandler"),
152
+ cython_extension("arraydatatype"),
153
+ cython_extension("errorchecker"),
154
+ cython_extension("vbo"),
155
+ cython_extension("nones_formathandler"),
156
+ cython_extension("latebind"),
157
+ ]
158
+ )
159
+ if sys.version_info[:2] >= (2, 7):
160
+ extensions.extend(
161
+ [
162
+ cython_extension("buffers_formathandler"),
163
+ ]
164
+ )
165
+
166
+ try:
167
+ import numpy
168
+ except ImportError:
169
+ sys.stderr.write("""Unable to import numpy, skipping numpy extension building\n""")
170
+ else:
171
+ if hasattr(numpy, "get_include"):
172
+ includeDirectories = [
173
+ numpy.get_include(),
174
+ ]
175
+ else:
176
+ includeDirectories = [
177
+ os.path.join(
178
+ os.path.dirname(numpy.__file__),
179
+ "core",
180
+ "include",
181
+ ),
182
+ ]
183
+ extensions.append(
184
+ cython_extension(
185
+ "numpy_formathandler",
186
+ includeDirectories,
187
+ )
188
+ )
189
+
190
+ if ( # Prevents running of setup during code introspection imports
191
+ __name__ == "__main__"
192
+ ):
193
+ # Workaround for Broken apple Python build params echoed in distutils
194
+ # Approach taken from the PyMongo driver. OS-X Python builds were created with
195
+ # non-existent flag, and distutils passes those flags to the extension
196
+ # build, newer clangs now treat those flags as errors rather than warnings.
197
+ import platform, sys
198
+
199
+ if sys.platform == "darwin" and "clang" in platform.python_compiler().lower():
200
+ from distutils.sysconfig import get_config_vars
201
+
202
+ res = get_config_vars()
203
+ for key in ("CFLAGS", "PY_CFLAGS"):
204
+ if key in res:
205
+ res[key] = res[key].replace("-mno-fused-madd", "")
206
+
207
+ extraArguments = {}
208
+ ### Now the actual set up call
209
+ if have_cython:
210
+ extraArguments["cmdclass"] = {
211
+ "build_ext": build_ext,
212
+ }
213
+ setup(
214
+ build_requires=['cython'],
215
+ install_requires=[pyopengl_requirement()],
216
+ options={
217
+ "sdist": {
218
+ "formats": ["gztar"],
219
+ "force_manifest": True,
220
+ },
221
+ },
222
+ ext_modules=extensions,
223
+ **extraArguments
224
+ )
@@ -292,7 +292,99 @@ cdef class Output(cArgConverter):
292
292
  cdef object c_call( self, tuple pyArgs, int index, object baseOperation ):
293
293
  """Return pyArgs[ self.index ]"""
294
294
  return self.arrayType.c_zeros( self.c_getSize(pyArgs), self.arrayType.typeConstant )
295
-
295
+
296
+ cdef object c_orInput( self, tuple pyArgs, int index ):
297
+ """Coerce a passed-in output array, refusing a lossy copy.
298
+
299
+ When the caller's array is already an acceptable buffer, asArray returns
300
+ it unchanged and the GL result is written straight back into it. When it
301
+ is the wrong type, asArray must *copy* it to match; if that copy is
302
+ smaller than the caller's buffer, the read is truncated into the copy and
303
+ never reaches the caller's array -- the silent "returns zeroes" bug.
304
+ Detect the shrinking copy and raise. Correctly-typed arrays are not
305
+ copied, so they never trip this.
306
+
307
+ Then the other question, which the count answers: an array shorter than
308
+ the call will write into is a heap overrun rather than an exception, so
309
+ it is refused. See ``Output.checkOutputSize`` in OpenGL/converters.py,
310
+ which is the same check for the pure-Python converter -- this one is
311
+ what runs where accelerate is installed, whichever dispatch layer the
312
+ entry points come from.
313
+ """
314
+ value = pyArgs[index]
315
+ result = self.arrayType.asArray( value )
316
+ if result is not value:
317
+ try:
318
+ rbytes = self.arrayType.arrayByteCount( result )
319
+ vbytes = self.arrayType.arrayByteCount( value )
320
+ except Exception:
321
+ # Not measurable -- a list has no byte count of its own -- so
322
+ # there is no shrinking coercion to detect. The size the call
323
+ # will write is still checked below.
324
+ rbytes = vbytes = 0
325
+ if rbytes < vbytes:
326
+ raise TypeError(
327
+ '%s: pass-in output array was coerced to a smaller buffer '
328
+ '(%d < %d bytes), so the GL result cannot be written back '
329
+ 'into your array. Pass a correctly-typed array, or None to '
330
+ 'have one allocated.' % ( self.name, rbytes, vbytes )
331
+ )
332
+ self.c_checkOutputSize( result, pyArgs )
333
+ return result
334
+
335
+ cdef int c_checkOutputSize( self, object array, tuple pyArgs ) except -1:
336
+ """Nothing to check: a fixed declared size is a maximum.
337
+
338
+ Which of it a call fills depends on the pname -- glGetVertexAttribiv
339
+ declares four and writes one for most of them -- so a shorter array is
340
+ legitimate here. :class:`SizedOutput` overrides this, because its size
341
+ is a count the caller passed and so says what will be written.
342
+ """
343
+ return 0
344
+
345
+ cdef int c_checkPromisedSize( self, object array, tuple pyArgs ) except -1:
346
+ """Refuse an output array smaller than the call will write into it.
347
+
348
+ Only a shortfall: a larger array is a caller deliberately reusing one
349
+ buffer for several calls, which is ordinary and safe.
350
+ """
351
+ cdef long wanted = 1
352
+ try:
353
+ shape = self.c_getSize( pyArgs )
354
+ except Exception:
355
+ return 0
356
+ if shape is None:
357
+ return 0
358
+ for dimension in shape:
359
+ try:
360
+ wanted = wanted * int(dimension)
361
+ except (TypeError, ValueError):
362
+ return 0
363
+ if wanted <= 0:
364
+ return 0
365
+ # Compared in bytes, not elements. The count is in units of the type
366
+ # the *declaration* names -- glGetBufferSubData's `size` is a byte
367
+ # count, glGenTextures' `n` is a count of GLuint -- and the caller may
368
+ # pass an array of some other type holding the same bytes.
369
+ # Only what carries its own length. A bare ctypes pointer does not --
370
+ # the hand-written wrappers in OpenGL/GL/exceptional.py pass
371
+ # `typedPointer` results straight down -- and arrayByteCount answers
372
+ # for one anyway, with the size of a single element.
373
+ if not hasattr( array, '__len__' ):
374
+ return 0
375
+ try:
376
+ wanted_bytes = wanted * ctypes.sizeof( self.arrayType.baseType )
377
+ held_bytes = self.arrayType.arrayByteCount( array )
378
+ except Exception:
379
+ return 0
380
+ if held_bytes < wanted_bytes:
381
+ raise ValueError(
382
+ '%s: output array holds %d byte(s), but the call will '
383
+ 'write %d. Pass a larger array, or None to have one '
384
+ 'allocated.' % ( self.name, held_bytes, wanted_bytes )
385
+ )
386
+ return 0
387
+
296
388
  def oldStyleReturn( self, object result, object baseOperation, tuple pyArgs, tuple cArgs ):
297
389
  """Retrieve cArgs[ self.index ]"""
298
390
  #TODO: make this a c_api-bearing value, not a Python function call
@@ -313,7 +405,7 @@ cdef class OutputOrInput( Output ):
313
405
  cdef object c_call( self, tuple pyArgs, int index, object baseOperation ):
314
406
  """Return pyArgs[ self.index ]"""
315
407
  if pyArgs[index] is not DO_OUTPUT[0] and pyArgs[index] is not DO_OUTPUT[1]:
316
- return self.arrayType.asArray( pyArgs[index] )
408
+ return self.c_orInput( pyArgs, index )
317
409
  return self.arrayType.c_zeros( self.c_getSize(pyArgs), self.arrayType.typeConstant )
318
410
 
319
411
  cdef class SizedOutput( Output ):
@@ -334,6 +426,24 @@ cdef class SizedOutput( Output ):
334
426
  def finalise( self, wrapper ):
335
427
  super( SizedOutput,self).finalise( wrapper )
336
428
  self.index = wrapper.pyArgIndex( self.specifier )
429
+ cdef int c_checkOutputSize( self, object array, tuple pyArgs ) except -1:
430
+ """Check the size only where it says what this call will write.
431
+
432
+ It does when it comes from a *count* the caller passed --
433
+ glGenTextures(n, names) writes n, glGetBufferSubData writes `size`
434
+ bytes -- which the declaration spells `size=lambda x: (x,)`.
435
+
436
+ It does not when it comes from a table keyed on a *pname*, which says
437
+ how large that piece of state is in total; how much of it a call fills
438
+ is the call's business, and glGetIntegeri_v writes one element of a
439
+ three-element pname at a time. The declaration spells that
440
+ `size=<a dict>`, handed on as its `__getitem__` -- so the dict it is
441
+ bound to is what tells the two apart.
442
+ """
443
+ if isinstance( getattr( self.lookup, '__self__', None ), dict ):
444
+ return 0
445
+ return self.c_checkPromisedSize( array, pyArgs )
446
+
337
447
  cdef tuple c_getSize( self, tuple pyArgs ):
338
448
  """Retrieve the array size for this argument"""
339
449
  try:
@@ -353,7 +463,7 @@ cdef class SizedOutputOrInput( SizedOutput ):
353
463
  cdef object c_call( self, tuple pyArgs, int index, object baseOperation ):
354
464
  """Return pyArgs[ self.index ]"""
355
465
  if pyArgs[index] is not DO_OUTPUT[0] and pyArgs[index] is not DO_OUTPUT[1]:
356
- return self.arrayType.asArray( pyArgs[index] )
466
+ return self.c_orInput( pyArgs, index )
357
467
  return self.arrayType.c_zeros( self.c_getSize(pyArgs), self.arrayType.typeConstant )
358
468
 
359
469