0
# OpenGL Integration
1
2
Integration with OpenGL for graphics programming, allowing sharing of buffer objects and textures between CUDA and OpenGL contexts. This enables seamless interoperability for graphics and compute applications.
3
4
## Capabilities
5
6
### Initialization and Context Management
7
8
Initialize OpenGL integration and manage shared contexts between CUDA and OpenGL.
9
10
```python { .api }
11
def init() -> None:
12
"""
13
Initialize OpenGL integration.
14
15
Must be called before any OpenGL interoperability functions.
16
Requires an active OpenGL context.
17
"""
18
19
def make_context(device: Device, flags: int = 0) -> Context:
20
"""
21
Create CUDA context with OpenGL interoperability.
22
23
Parameters:
24
- device: Device, CUDA device
25
- flags: int, context creation flags
26
27
Returns:
28
Context: CUDA context with OpenGL support
29
"""
30
```
31
32
### Buffer Object Interoperability
33
34
Share OpenGL buffer objects with CUDA for compute operations on graphics data.
35
36
```python { .api }
37
class BufferObject:
38
"""OpenGL buffer object wrapper for CUDA interoperability."""
39
40
def __init__(self, buffer_id: int):
41
"""
42
Create buffer object from OpenGL buffer ID.
43
44
Parameters:
45
- buffer_id: int, OpenGL buffer object ID
46
"""
47
48
def register(self, flags: int = 0) -> RegisteredBuffer:
49
"""
50
Register buffer for CUDA access.
51
52
Parameters:
53
- flags: int, registration flags
54
55
Returns:
56
RegisteredBuffer: registered buffer for mapping
57
"""
58
59
class RegisteredBuffer:
60
"""Registered OpenGL buffer for CUDA access."""
61
62
def map(self, flags: int = 0) -> BufferObjectMapping:
63
"""
64
Map buffer for CUDA access.
65
66
Parameters:
67
- flags: int, mapping flags
68
69
Returns:
70
BufferObjectMapping: mapped buffer for CUDA operations
71
"""
72
73
def unregister(self) -> None:
74
"""Unregister buffer from CUDA."""
75
76
class BufferObjectMapping:
77
"""Mapped OpenGL buffer accessible from CUDA."""
78
79
def device_ptr(self) -> DeviceAllocation:
80
"""
81
Get CUDA device pointer to buffer data.
82
83
Returns:
84
DeviceAllocation: device pointer to buffer memory
85
"""
86
87
def size(self) -> int:
88
"""
89
Get buffer size in bytes.
90
91
Returns:
92
int: buffer size in bytes
93
"""
94
95
def unmap(self) -> None:
96
"""Unmap buffer from CUDA access."""
97
98
def __enter__(self) -> BufferObjectMapping:
99
"""Context manager entry."""
100
return self
101
102
def __exit__(self, exc_type, exc_val, exc_tb) -> None:
103
"""Context manager exit (automatically unmaps)."""
104
self.unmap()
105
```
106
107
### Image and Texture Interoperability
108
109
Share OpenGL textures and images with CUDA for image processing operations.
110
111
```python { .api }
112
class RegisteredImage:
113
"""Registered OpenGL image/texture for CUDA access."""
114
115
def __init__(self, image_id: int, target: int, flags: int = 0):
116
"""
117
Register OpenGL image/texture for CUDA access.
118
119
Parameters:
120
- image_id: int, OpenGL texture/image ID
121
- target: int, OpenGL texture target (GL_TEXTURE_2D, etc.)
122
- flags: int, registration flags
123
"""
124
125
def map(self, flags: int = 0) -> RegisteredMapping:
126
"""
127
Map image for CUDA access.
128
129
Parameters:
130
- flags: int, mapping flags
131
132
Returns:
133
RegisteredMapping: mapped image for CUDA operations
134
"""
135
136
def unregister(self) -> None:
137
"""Unregister image from CUDA."""
138
139
class RegisteredMapping:
140
"""Mapped OpenGL image accessible from CUDA."""
141
142
def array(self) -> Array:
143
"""
144
Get CUDA array from mapped image.
145
146
Returns:
147
Array: CUDA array representing image data
148
"""
149
150
def device_ptr_and_size(self) -> tuple[DeviceAllocation, int]:
151
"""
152
Get device pointer and size.
153
154
Returns:
155
tuple: (device_pointer, size_in_bytes)
156
"""
157
158
def unmap(self) -> None:
159
"""Unmap image from CUDA access."""
160
161
def __enter__(self) -> RegisteredMapping:
162
"""Context manager entry."""
163
return self
164
165
def __exit__(self, exc_type, exc_val, exc_tb) -> None:
166
"""Context manager exit (automatically unmaps)."""
167
self.unmap()
168
```
169
170
### Graphics Resource Management
171
172
Manage graphics resources and their CUDA interoperability state.
173
174
```python { .api }
175
def graphics_map_flags() -> object:
176
"""
177
Get graphics mapping flags namespace.
178
179
Returns:
180
object: namespace with mapping flag constants
181
"""
182
183
def register_buffer_object(buffer_id: int, flags: int = 0) -> RegisteredBuffer:
184
"""
185
Register OpenGL buffer object for CUDA access.
186
187
Parameters:
188
- buffer_id: int, OpenGL buffer object ID
189
- flags: int, registration flags
190
191
Returns:
192
RegisteredBuffer: registered buffer object
193
"""
194
195
def register_image(image_id: int, target: int, flags: int = 0) -> RegisteredImage:
196
"""
197
Register OpenGL image/texture for CUDA access.
198
199
Parameters:
200
- image_id: int, OpenGL texture/image ID
201
- target: int, OpenGL texture target
202
- flags: int, registration flags
203
204
Returns:
205
RegisteredImage: registered image object
206
"""
207
208
def unregister_buffer_object(registered_buffer: RegisteredBuffer) -> None:
209
"""
210
Unregister buffer object from CUDA.
211
212
Parameters:
213
- registered_buffer: RegisteredBuffer, buffer to unregister
214
"""
215
216
def unregister_image(registered_image: RegisteredImage) -> None:
217
"""
218
Unregister image from CUDA.
219
220
Parameters:
221
- registered_image: RegisteredImage, image to unregister
222
"""
223
```
224
225
### Synchronization
226
227
Synchronize operations between CUDA and OpenGL contexts.
228
229
```python { .api }
230
def gl_sync() -> None:
231
"""
232
Synchronize OpenGL operations.
233
234
Ensures all pending OpenGL operations complete before CUDA operations.
235
"""
236
237
def cuda_gl_sync() -> None:
238
"""
239
Synchronize CUDA-OpenGL operations.
240
241
Ensures proper ordering between CUDA and OpenGL operations.
242
"""
243
```
244
245
## Usage Examples
246
247
### Basic Buffer Sharing
248
249
```python
250
import pycuda.gl as cuda_gl
251
import pycuda.driver as cuda
252
import pycuda.gpuarray as gpuarray
253
import OpenGL.GL as gl
254
import numpy as np
255
256
# Initialize OpenGL integration
257
cuda_gl.init()
258
259
# Create OpenGL vertex buffer
260
vertex_data = np.array([[0.0, 0.0], [1.0, 0.0], [0.5, 1.0]], dtype=np.float32)
261
vbo = gl.glGenBuffers(1)
262
gl.glBindBuffer(gl.GL_ARRAY_BUFFER, vbo)
263
gl.glBufferData(gl.GL_ARRAY_BUFFER, vertex_data.nbytes, vertex_data, gl.GL_DYNAMIC_DRAW)
264
265
# Register buffer with CUDA
266
cuda_buffer = cuda_gl.BufferObject(vbo)
267
registered_buffer = cuda_buffer.register()
268
269
# Map buffer for CUDA access
270
with registered_buffer.map() as mapping:
271
# Get device pointer
272
dev_ptr = mapping.device_ptr()
273
size = mapping.size()
274
275
# Create GPU array from buffer
276
gpu_array = gpuarray.GPUArray(vertex_data.shape, vertex_data.dtype, gpudata=dev_ptr)
277
278
# Perform CUDA operations on vertex data
279
gpu_array *= 2.0 # Scale vertices
280
281
# Buffer is automatically unmapped when exiting context
282
# Vertex data is now modified and available to OpenGL
283
```
284
285
### Texture Processing
286
287
```python
288
import pycuda.gl as cuda_gl
289
import OpenGL.GL as gl
290
291
# Create OpenGL texture
292
texture_id = gl.glGenTextures(1)
293
gl.glBindTexture(gl.GL_TEXTURE_2D, texture_id)
294
gl.glTexImage2D(gl.GL_TEXTURE_2D, 0, gl.GL_RGBA32F, 512, 512, 0,
295
gl.GL_RGBA, gl.GL_FLOAT, None)
296
297
# Register texture with CUDA
298
registered_image = cuda_gl.RegisteredImage(texture_id, gl.GL_TEXTURE_2D)
299
300
# Map texture for CUDA access
301
with registered_image.map() as mapping:
302
# Get CUDA array from texture
303
cuda_array = mapping.array()
304
305
# Perform image processing operations
306
# (Would typically use custom kernels here)
307
308
# Process image with CUDA kernels...
309
pass
310
311
# Texture is automatically unmapped and available to OpenGL for rendering
312
```
313
314
### Ping-Pong Rendering with Compute
315
316
```python
317
class CudaGLInterop:
318
def __init__(self, width, height):
319
self.width = width
320
self.height = height
321
322
# Initialize OpenGL integration
323
cuda_gl.init()
324
325
# Create ping-pong textures
326
self.textures = gl.glGenTextures(2)
327
for i, tex_id in enumerate(self.textures):
328
gl.glBindTexture(gl.GL_TEXTURE_2D, tex_id)
329
gl.glTexImage2D(gl.GL_TEXTURE_2D, 0, gl.GL_RGBA32F, width, height, 0,
330
gl.GL_RGBA, gl.GL_FLOAT, None)
331
gl.glTexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MIN_FILTER, gl.GL_NEAREST)
332
gl.glTexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MAG_FILTER, gl.GL_NEAREST)
333
334
# Register textures with CUDA
335
self.registered_images = [
336
cuda_gl.RegisteredImage(tex_id, gl.GL_TEXTURE_2D)
337
for tex_id in self.textures
338
]
339
340
self.current_texture = 0
341
342
def process_frame(self):
343
"""Process current texture with CUDA and swap buffers."""
344
# Map current texture for reading
345
with self.registered_images[self.current_texture].map() as input_mapping:
346
# Map next texture for writing
347
next_texture = (self.current_texture + 1) % 2
348
with self.registered_images[next_texture].map() as output_mapping:
349
350
# Get CUDA arrays
351
input_array = input_mapping.array()
352
output_array = output_mapping.array()
353
354
# Perform CUDA processing
355
self.cuda_process(input_array, output_array)
356
357
# Swap current texture
358
self.current_texture = (self.current_texture + 1) % 2
359
360
# Synchronize for OpenGL rendering
361
cuda_gl.cuda_gl_sync()
362
363
def cuda_process(self, input_array, output_array):
364
"""Perform CUDA processing on texture data."""
365
# Custom CUDA kernel processing would go here
366
pass
367
368
def get_current_texture(self):
369
"""Get current texture ID for OpenGL rendering."""
370
return self.textures[self.current_texture]
371
```
372
373
### Performance Considerations
374
375
```python
376
# Efficient buffer management
377
class GLBufferPool:
378
def __init__(self, buffer_size, pool_size=4):
379
self.buffer_size = buffer_size
380
self.available_buffers = []
381
self.mapped_buffers = {}
382
383
# Pre-allocate buffer pool
384
for _ in range(pool_size):
385
# Create OpenGL buffer
386
vbo = gl.glGenBuffers(1)
387
gl.glBindBuffer(gl.GL_ARRAY_BUFFER, vbo)
388
gl.glBufferData(gl.GL_ARRAY_BUFFER, buffer_size, None, gl.GL_STREAM_DRAW)
389
390
# Register with CUDA
391
cuda_buffer = cuda_gl.BufferObject(vbo)
392
registered = cuda_buffer.register()
393
394
self.available_buffers.append((vbo, registered))
395
396
def get_buffer(self):
397
"""Get available buffer from pool."""
398
if not self.available_buffers:
399
raise RuntimeError("No available buffers in pool")
400
401
vbo, registered = self.available_buffers.pop()
402
mapping = registered.map()
403
self.mapped_buffers[vbo] = (registered, mapping)
404
405
return vbo, mapping
406
407
def return_buffer(self, vbo):
408
"""Return buffer to pool."""
409
if vbo in self.mapped_buffers:
410
registered, mapping = self.mapped_buffers.pop(vbo)
411
mapping.unmap()
412
self.available_buffers.append((vbo, registered))
413
```
414
415
## Constants and Flags
416
417
```python { .api }
418
# Graphics resource mapping flags
419
graphics_map_flags = SimpleNamespace(
420
NONE=0,
421
READ_ONLY=1,
422
WRITE_DISCARD=2
423
)
424
425
# Graphics resource registration flags
426
graphics_register_flags = SimpleNamespace(
427
NONE=0,
428
SURFACE_LDST=1,
429
TEXTURE_GATHER=2
430
)
431
```