A ctypes-based wrapper for GLFW3 that provides Python bindings for OpenGL, OpenGL ES, and Vulkan development on desktop platforms.
—
Vulkan surface creation, instance management, and Vulkan function loading for modern low-level graphics programming.
Check for Vulkan support and loader availability.
def vulkan_supported() -> bool:
"""
Check whether the Vulkan loader has been found.
This function returns whether the Vulkan loader and any minimally
functional ICD have been found.
Returns:
bool: True if Vulkan is supported, False otherwise
"""Query required Vulkan instance extensions for presentation support.
def get_required_instance_extensions() -> list[str]:
"""
Get the Vulkan instance extensions required by GLFW.
This function returns a list of names of Vulkan instance extensions
required by GLFW for creating Vulkan surfaces for GLFW windows.
Returns:
list[str]: List of required extension names
"""Create Vulkan surfaces for windows to enable Vulkan rendering.
def create_window_surface(instance, window, allocator, surface) -> int:
"""
Create a Vulkan surface for the specified window.
This function creates a Vulkan surface for the specified window.
Parameters:
instance: Vulkan instance handle (VkInstance)
window: Window to create surface for
allocator: Allocator to use, or None (VkAllocationCallbacks*)
surface: Where to store the handle of the surface (VkSurfaceKHR*)
Returns:
int: VkResult - VK_SUCCESS if successful
"""Check physical device presentation support for Vulkan queues.
def get_physical_device_presentation_support(instance, device, queuefamily: int) -> int:
"""
Check whether the specified queue family supports presentation.
This function returns whether the specified queue family of the
specified physical device supports presentation to the platform GLFW was built for.
Parameters:
instance: Vulkan instance handle (VkInstance)
device: Physical device handle (VkPhysicalDevice)
queuefamily: Queue family index
Returns:
int: 1 if supported, 0 if not supported
"""Load Vulkan functions for the current instance.
def get_instance_proc_address(instance, procname: str) -> ctypes.c_void_p:
"""
Get the address of the specified Vulkan instance function.
This function returns the address of the specified Vulkan core or
extension function for the specified instance.
Parameters:
instance: Vulkan instance handle (VkInstance), or None for instance-independent functions
procname: ASCII encoded name of the function
Returns:
ctypes.c_void_p: Function address, or None if function is not available
"""Configure the Vulkan loader before initialization (advanced usage).
def init_vulkan_loader(loader) -> None:
"""
Set the desired Vulkan vkGetInstanceProcAddr function.
This function sets the vkGetInstanceProcAddr function that GLFW will use for all
Vulkan related entry point queries.
Parameters:
loader: vkGetInstanceProcAddr function, or None to use default
"""When creating windows for Vulkan rendering, set appropriate window hints:
# Vulkan-specific window hints
CLIENT_API: int = 0x00022001
NO_API: int = 0 # Disable OpenGL context creation for Vulkan
# Use with window_hint:
# glfw.window_hint(glfw.CLIENT_API, glfw.NO_API)import glfw
import ctypes
# Initialize GLFW
glfw.init()
# Check Vulkan support
if not glfw.vulkan_supported():
glfw.terminate()
raise Exception("Vulkan not supported")
# Get required extensions
extensions = glfw.get_required_instance_extensions()
print(f"Required Vulkan extensions: {extensions}")
# Create window without OpenGL context
glfw.window_hint(glfw.CLIENT_API, glfw.NO_API)
glfw.window_hint(glfw.RESIZABLE, glfw.FALSE)
window = glfw.create_window(800, 600, "Vulkan Window", None, None)
if not window:
glfw.terminate()
raise Exception("Failed to create window")
# ... Vulkan instance creation with required extensions ...
# instance = create_vulkan_instance_with_extensions(extensions)
# Create Vulkan surface
# surface = ctypes.c_void_p()
# result = glfw.create_window_surface(instance, window, None, ctypes.byref(surface))
# if result != VK_SUCCESS:
# raise Exception("Failed to create Vulkan surface")
glfw.terminate()import glfw
import ctypes
glfw.init()
if not glfw.vulkan_supported():
raise Exception("Vulkan not supported")
# Load Vulkan functions
vk_create_instance = glfw.get_instance_proc_address(None, "vkCreateInstance")
vk_enumerate_instance_extensions = glfw.get_instance_proc_address(None, "vkEnumerateInstanceExtensionProperties")
if vk_create_instance:
print("Successfully loaded vkCreateInstance")
# After creating instance, load instance-specific functions
# instance = ... # Created Vulkan instance
# vk_create_device = glfw.get_instance_proc_address(instance, "vkCreateDevice")
# vk_get_physical_devices = glfw.get_instance_proc_address(instance, "vkEnumeratePhysicalDevices")
glfw.terminate()import glfw
import ctypes
def create_vulkan_window():
glfw.init()
# Verify Vulkan support
if not glfw.vulkan_supported():
glfw.terminate()
raise Exception("Vulkan is not supported")
# Get required instance extensions
glfw_extensions = glfw.get_required_instance_extensions()
print(f"GLFW requires these Vulkan extensions: {glfw_extensions}")
# Create window for Vulkan (no OpenGL context)
glfw.window_hint(glfw.CLIENT_API, glfw.NO_API)
glfw.window_hint(glfw.RESIZABLE, glfw.TRUE)
window = glfw.create_window(1024, 768, "Vulkan Application", None, None)
if not window:
glfw.terminate()
raise Exception("Failed to create GLFW window")
return window, glfw_extensions
def check_device_presentation_support(instance, physical_device, queue_family_index):
"""Check if a queue family supports presentation to GLFW windows."""
return glfw.get_physical_device_presentation_support(
instance, physical_device, queue_family_index
) == 1
# Usage
try:
window, required_extensions = create_vulkan_window()
# ... Create Vulkan instance with required_extensions ...
# ... Enumerate physical devices ...
# ... Check presentation support with check_device_presentation_support ...
# ... Create logical device with presentation-capable queue ...
# ... Create surface with glfw.create_window_surface ...
# Main loop
while not glfw.window_should_close(window):
glfw.poll_events()
# Vulkan rendering commands
# ... vkQueueSubmit, vkQueuePresentKHR, etc. ...
finally:
glfw.terminate()import glfw
import ctypes
class VulkanSurface:
def __init__(self, instance, window):
self.instance = instance
self.window = window
self.surface = ctypes.c_void_p()
# Create the surface
result = glfw.create_window_surface(
instance, window, None, ctypes.byref(self.surface)
)
if result != 0: # VK_SUCCESS = 0
raise Exception(f"Failed to create Vulkan surface: {result}")
def get_handle(self):
return self.surface.value
def cleanup(self):
# In a real application, you would call vkDestroySurfaceKHR here
# vkDestroySurfaceKHR(self.instance, self.surface, None)
pass
# Usage example
glfw.init()
if glfw.vulkan_supported():
glfw.window_hint(glfw.CLIENT_API, glfw.NO_API)
window = glfw.create_window(800, 600, "Vulkan Surface", None, None)
# ... create Vulkan instance ...
# instance = create_instance()
# surface = VulkanSurface(instance, window)
# print(f"Created surface: 0x{surface.get_handle():x}")
# ... use surface for swapchain creation ...
# surface.cleanup()
glfw.terminate()import glfw
def get_vulkan_extensions_with_validation():
"""Get Vulkan extensions including validation layer requirements."""
# Get GLFW required extensions
glfw_extensions = glfw.get_required_instance_extensions()
# Add debug/validation extensions
validation_extensions = ["VK_EXT_debug_utils"]
# Combine extensions
all_extensions = glfw_extensions + validation_extensions
return all_extensions
def setup_vulkan_debug_callback():
"""Set up Vulkan debug callback for validation layers."""
# Load debug function
vk_create_debug_utils_messenger = glfw.get_instance_proc_address(
None, "vkCreateDebugUtilsMessengerEXT"
)
if vk_create_debug_utils_messenger:
print("Debug utils extension available")
# ... set up debug callback ...
else:
print("Debug utils extension not available")
# Usage
glfw.init()
if glfw.vulkan_supported():
extensions = get_vulkan_extensions_with_validation()
print(f"Extensions for Vulkan with validation: {extensions}")
# ... create instance with validation layers and extensions ...
# setup_vulkan_debug_callback()
glfw.terminate()import glfw
import ctypes
def create_vulkan_windows(count=2):
"""Create multiple windows for Vulkan rendering."""
glfw.init()
if not glfw.vulkan_supported():
raise Exception("Vulkan not supported")
glfw.window_hint(glfw.CLIENT_API, glfw.NO_API)
windows = []
for i in range(count):
window = glfw.create_window(
800, 600, f"Vulkan Window {i+1}", None, None
)
if not window:
# Clean up previously created windows
for w in windows:
glfw.destroy_window(w)
glfw.terminate()
raise Exception(f"Failed to create window {i+1}")
windows.append(window)
return windows
def create_surfaces_for_windows(instance, windows):
"""Create Vulkan surfaces for multiple windows."""
surfaces = []
for i, window in enumerate(windows):
surface = ctypes.c_void_p()
result = glfw.create_window_surface(
instance, window, None, ctypes.byref(surface)
)
if result != 0:
print(f"Failed to create surface for window {i+1}")
continue
surfaces.append(surface.value)
return surfaces
# Usage
try:
windows = create_vulkan_windows(2)
# ... create Vulkan instance ...
# surfaces = create_surfaces_for_windows(instance, windows)
# Main loop handling multiple windows
while any(not glfw.window_should_close(w) for w in windows):
glfw.poll_events()
for i, window in enumerate(windows):
if not glfw.window_should_close(window):
# Render to window i
# ... Vulkan rendering for this window/surface ...
pass
finally:
glfw.terminate()Install with Tessl CLI
npx tessl i tessl/pypi-glfw