Skip to content

Commit 853340b

Browse files
committed
graphics: allow resource-scoped context managers
1 parent 0c9a981 commit 853340b

2 files changed

Lines changed: 35 additions & 23 deletions

File tree

‎cuda_core/cuda/core/_graphics.pyx‎

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -73,13 +73,14 @@ cdef class GraphicsResource:
7373
view = StridedMemoryView.from_buffer(buf, shape=(256,), dtype=np.float32)
7474
# view.ptr is a CUDA device pointer into the GL buffer
7575
76-
Or use explicit control for render loops:
76+
Or scope registration separately from mapping:
7777
7878
.. code-block:: python
7979
80-
buf = resource.map(stream=s)
81-
# ... launch kernels using buf.handle, buf.size ...
82-
buf.close()
80+
with GraphicsResource.from_gl_buffer(vbo) as resource:
81+
with resource.map(stream=s) as buf:
82+
# ... launch kernels using buf.handle, buf.size ...
83+
pass
8384
"""
8485

8586
def __init__(self):
@@ -110,12 +111,21 @@ cdef class GraphicsResource:
110111
with GraphicsResource.from_gl_buffer(vbo, stream=s) as buf:
111112
view = StridedMemoryView.from_buffer(buf, shape=(256,), dtype=np.float32)
112113

114+
If omitted, the returned resource can still be used as a context
115+
manager to scope registration and automatic cleanup::
116+
117+
with GraphicsResource.from_gl_buffer(vbo) as resource:
118+
with resource.map(stream=s) as buf:
119+
...
120+
113121
Returns
114122
-------
115123
GraphicsResource
116124
A new graphics resource wrapping the registered GL buffer.
117-
If *stream* was given, the returned resource can be used directly
118-
as a context manager.
125+
The returned resource can be used as a context manager. If
126+
*stream* was given, entering maps the resource and yields a
127+
:class:`~cuda.core.Buffer`; otherwise entering yields the
128+
:class:`GraphicsResource` itself and closes it on exit.
119129

120130
Raises
121131
------
@@ -289,21 +299,12 @@ cdef class GraphicsResource:
289299

290300
def __enter__(self):
291301
if self._context_manager_stream is None:
292-
raise RuntimeError(
293-
"GraphicsResource context manager requires a stream; "
294-
"use resource.map(stream=...) or pass stream= to from_gl_buffer()"
295-
)
302+
return self
296303
self._entered_buffer = self.map(stream=self._context_manager_stream)
297304
return self._entered_buffer
298305

299306
def __exit__(self, exc_type, exc_val, exc_tb):
300-
cdef object buf_obj = self._entered_buffer
301-
cdef Buffer buf
302-
self._entered_buffer = None
303-
if buf_obj is not None:
304-
buf = <Buffer>buf_obj
305-
if buf._h_ptr:
306-
buf.close()
307+
self.close()
307308
return False
308309

309310
cpdef close(self, stream=None):

‎cuda_core/tests/test_graphics.py‎

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -303,13 +303,24 @@ def test_from_gl_buffer_with_stream_context_manager(self):
303303
assert buf.handle == 0
304304
assert buf.size == 0
305305

306-
def test_resource_context_manager_requires_stream(self):
306+
def test_resource_context_manager_auto_closes(self):
307307
with _gl_context_and_buffer(nbytes=4096) as (gl_buf, _):
308-
resource = GraphicsResource.from_gl_buffer(gl_buf, flags="write_discard")
309-
with pytest.raises(RuntimeError, match="requires a stream"):
310-
with resource as _buf:
311-
pass
312-
resource.close()
308+
with GraphicsResource.from_gl_buffer(gl_buf, flags="write_discard") as resource:
309+
assert isinstance(resource, GraphicsResource)
310+
assert resource.handle != 0
311+
assert not resource.is_mapped
312+
assert resource.handle == 0
313+
314+
def test_resource_context_manager_can_map_inside_scope(self):
315+
with _gl_context_and_buffer(nbytes=4096) as (gl_buf, _):
316+
stream = _create_stream()
317+
with GraphicsResource.from_gl_buffer(gl_buf, flags="write_discard") as resource:
318+
with resource.map(stream=stream) as buf:
319+
assert isinstance(buf, Buffer)
320+
assert resource.is_mapped
321+
assert buf.handle != 0
322+
assert resource.handle == 0
323+
assert not resource.is_mapped
313324

314325
def test_map_with_stream(self):
315326
with _gl_context_and_buffer(nbytes=4096) as (gl_buf, nbytes):

0 commit comments

Comments
 (0)