├── .editorconfig ├── .gitattributes ├── .gitignore ├── GeneratorOptions.zig ├── LICENSE.txt ├── LICENSES ├── Apache-2.0.txt └── MIT.txt ├── README.md ├── api_registry.zig ├── build.zig ├── build.zig.zon ├── updateApiRegistry.ps1 └── zigglgen.zig /.editorconfig: -------------------------------------------------------------------------------- 1 | # © 2024 Carl Åstholm 2 | # SPDX-License-Identifier: MIT 3 | 4 | root = true 5 | 6 | [*] 7 | indent_style = space 8 | indent_size = 4 9 | tab_width = 8 10 | end_of_line = lf 11 | charset = utf-8 12 | trim_trailing_whitespace = true 13 | insert_final_newline = true 14 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # © 2024 Carl Åstholm 2 | # SPDX-License-Identifier: MIT 3 | 4 | * text=auto eol=lf 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # © 2024 Carl Åstholm 2 | # SPDX-License-Identifier: MIT 3 | 4 | .zig-cache/ 5 | zig-out/ 6 | -------------------------------------------------------------------------------- /GeneratorOptions.zig: -------------------------------------------------------------------------------- 1 | // © 2013-2020 The Khronos Group Inc. 2 | // © 2024 Carl Åstholm 3 | // SPDX-License-Identifier: Apache-2.0 AND MIT 4 | 5 | // This file was generated by 'updateApiRegistry.ps1'. 6 | // OpenGL XML API Registry revision: b53ca669bea4715b6d5fa53c459f47a1fecd7944 7 | 8 | api: Api, 9 | version: Version, 10 | profile: ?Profile = null, 11 | extensions: []const Extension = &.{}, 12 | 13 | pub const Api = enum { gl, gles, glsc }; 14 | 15 | pub const Version = enum { 16 | @"1.0", 17 | @"1.1", 18 | @"1.2", 19 | @"1.3", 20 | @"1.4", 21 | @"1.5", 22 | @"2.0", 23 | @"2.1", 24 | @"3.0", 25 | @"3.1", 26 | @"3.2", 27 | @"3.3", 28 | @"4.0", 29 | @"4.1", 30 | @"4.2", 31 | @"4.3", 32 | @"4.4", 33 | @"4.5", 34 | @"4.6", 35 | }; 36 | 37 | pub const Profile = enum { core, compatibility, common, common_lite }; 38 | 39 | pub const Extension = enum { 40 | @"3DFX_multisample", 41 | @"3DFX_tbuffer", 42 | @"3DFX_texture_compression_FXT1", 43 | AMD_blend_minmax_factor, 44 | AMD_compressed_3DC_texture, 45 | AMD_compressed_ATC_texture, 46 | AMD_conservative_depth, 47 | AMD_debug_output, 48 | AMD_depth_clamp_separate, 49 | AMD_draw_buffers_blend, 50 | AMD_framebuffer_multisample_advanced, 51 | AMD_framebuffer_sample_positions, 52 | AMD_gcn_shader, 53 | AMD_gpu_shader_half_float, 54 | AMD_gpu_shader_int16, 55 | AMD_gpu_shader_int64, 56 | AMD_interleaved_elements, 57 | AMD_multi_draw_indirect, 58 | AMD_name_gen_delete, 59 | AMD_occlusion_query_event, 60 | AMD_performance_monitor, 61 | AMD_pinned_memory, 62 | AMD_program_binary_Z400, 63 | AMD_query_buffer_object, 64 | AMD_sample_positions, 65 | AMD_seamless_cubemap_per_texture, 66 | AMD_shader_atomic_counter_ops, 67 | AMD_shader_ballot, 68 | AMD_shader_explicit_vertex_parameter, 69 | AMD_shader_gpu_shader_half_float_fetch, 70 | AMD_shader_image_load_store_lod, 71 | AMD_shader_stencil_export, 72 | AMD_shader_trinary_minmax, 73 | AMD_sparse_texture, 74 | AMD_stencil_operation_extended, 75 | AMD_texture_gather_bias_lod, 76 | AMD_texture_texture4, 77 | AMD_transform_feedback3_lines_triangles, 78 | AMD_transform_feedback4, 79 | AMD_vertex_shader_layer, 80 | AMD_vertex_shader_tessellator, 81 | AMD_vertex_shader_viewport_index, 82 | ANDROID_extension_pack_es31a, 83 | ANGLE_depth_texture, 84 | ANGLE_framebuffer_blit, 85 | ANGLE_framebuffer_multisample, 86 | ANGLE_instanced_arrays, 87 | ANGLE_pack_reverse_row_order, 88 | ANGLE_program_binary, 89 | ANGLE_texture_compression_dxt3, 90 | ANGLE_texture_compression_dxt5, 91 | ANGLE_texture_usage, 92 | ANGLE_translated_shader_source, 93 | APPLE_aux_depth_stencil, 94 | APPLE_client_storage, 95 | APPLE_clip_distance, 96 | APPLE_color_buffer_packed_float, 97 | APPLE_copy_texture_levels, 98 | APPLE_element_array, 99 | APPLE_fence, 100 | APPLE_float_pixels, 101 | APPLE_flush_buffer_range, 102 | APPLE_framebuffer_multisample, 103 | APPLE_object_purgeable, 104 | APPLE_rgb_422, 105 | APPLE_row_bytes, 106 | APPLE_specular_vector, 107 | APPLE_sync, 108 | APPLE_texture_2D_limited_npot, 109 | APPLE_texture_format_BGRA8888, 110 | APPLE_texture_max_level, 111 | APPLE_texture_packed_float, 112 | APPLE_texture_range, 113 | APPLE_transform_hint, 114 | APPLE_vertex_array_object, 115 | APPLE_vertex_array_range, 116 | APPLE_vertex_program_evaluators, 117 | APPLE_ycbcr_422, 118 | ARB_ES2_compatibility, 119 | ARB_ES3_1_compatibility, 120 | ARB_ES3_2_compatibility, 121 | ARB_ES3_compatibility, 122 | ARB_arrays_of_arrays, 123 | ARB_base_instance, 124 | ARB_bindless_texture, 125 | ARB_blend_func_extended, 126 | ARB_buffer_storage, 127 | ARB_cl_event, 128 | ARB_clear_buffer_object, 129 | ARB_clear_texture, 130 | ARB_clip_control, 131 | ARB_color_buffer_float, 132 | ARB_compatibility, 133 | ARB_compressed_texture_pixel_storage, 134 | ARB_compute_shader, 135 | ARB_compute_variable_group_size, 136 | ARB_conditional_render_inverted, 137 | ARB_conservative_depth, 138 | ARB_copy_buffer, 139 | ARB_copy_image, 140 | ARB_cull_distance, 141 | ARB_debug_output, 142 | ARB_depth_buffer_float, 143 | ARB_depth_clamp, 144 | ARB_depth_texture, 145 | ARB_derivative_control, 146 | ARB_direct_state_access, 147 | ARB_draw_buffers, 148 | ARB_draw_buffers_blend, 149 | ARB_draw_elements_base_vertex, 150 | ARB_draw_indirect, 151 | ARB_draw_instanced, 152 | ARB_enhanced_layouts, 153 | ARB_explicit_attrib_location, 154 | ARB_explicit_uniform_location, 155 | ARB_fragment_coord_conventions, 156 | ARB_fragment_layer_viewport, 157 | ARB_fragment_program, 158 | ARB_fragment_program_shadow, 159 | ARB_fragment_shader, 160 | ARB_fragment_shader_interlock, 161 | ARB_framebuffer_no_attachments, 162 | ARB_framebuffer_object, 163 | ARB_framebuffer_sRGB, 164 | ARB_geometry_shader4, 165 | ARB_get_program_binary, 166 | ARB_get_texture_sub_image, 167 | ARB_gl_spirv, 168 | ARB_gpu_shader_fp64, 169 | ARB_gpu_shader_int64, 170 | ARB_gpu_shader5, 171 | ARB_half_float_pixel, 172 | ARB_half_float_vertex, 173 | ARB_imaging, 174 | ARB_indirect_parameters, 175 | ARB_instanced_arrays, 176 | ARB_internalformat_query, 177 | ARB_internalformat_query2, 178 | ARB_invalidate_subdata, 179 | ARB_map_buffer_alignment, 180 | ARB_map_buffer_range, 181 | ARB_matrix_palette, 182 | ARB_multi_bind, 183 | ARB_multi_draw_indirect, 184 | ARB_multisample, 185 | ARB_multitexture, 186 | ARB_occlusion_query, 187 | ARB_occlusion_query2, 188 | ARB_parallel_shader_compile, 189 | ARB_pipeline_statistics_query, 190 | ARB_pixel_buffer_object, 191 | ARB_point_parameters, 192 | ARB_point_sprite, 193 | ARB_polygon_offset_clamp, 194 | ARB_post_depth_coverage, 195 | ARB_program_interface_query, 196 | ARB_provoking_vertex, 197 | ARB_query_buffer_object, 198 | ARB_robust_buffer_access_behavior, 199 | ARB_robustness, 200 | ARB_robustness_isolation, 201 | ARB_sample_locations, 202 | ARB_sample_shading, 203 | ARB_sampler_objects, 204 | ARB_seamless_cube_map, 205 | ARB_seamless_cubemap_per_texture, 206 | ARB_separate_shader_objects, 207 | ARB_shader_atomic_counter_ops, 208 | ARB_shader_atomic_counters, 209 | ARB_shader_ballot, 210 | ARB_shader_bit_encoding, 211 | ARB_shader_clock, 212 | ARB_shader_draw_parameters, 213 | ARB_shader_group_vote, 214 | ARB_shader_image_load_store, 215 | ARB_shader_image_size, 216 | ARB_shader_objects, 217 | ARB_shader_precision, 218 | ARB_shader_stencil_export, 219 | ARB_shader_storage_buffer_object, 220 | ARB_shader_subroutine, 221 | ARB_shader_texture_image_samples, 222 | ARB_shader_texture_lod, 223 | ARB_shader_viewport_layer_array, 224 | ARB_shading_language_100, 225 | ARB_shading_language_420pack, 226 | ARB_shading_language_include, 227 | ARB_shading_language_packing, 228 | ARB_shadow, 229 | ARB_shadow_ambient, 230 | ARB_sparse_buffer, 231 | ARB_sparse_texture, 232 | ARB_sparse_texture_clamp, 233 | ARB_sparse_texture2, 234 | ARB_spirv_extensions, 235 | ARB_stencil_texturing, 236 | ARB_sync, 237 | ARB_tessellation_shader, 238 | ARB_texture_barrier, 239 | ARB_texture_border_clamp, 240 | ARB_texture_buffer_object, 241 | ARB_texture_buffer_object_rgb32, 242 | ARB_texture_buffer_range, 243 | ARB_texture_compression, 244 | ARB_texture_compression_bptc, 245 | ARB_texture_compression_rgtc, 246 | ARB_texture_cube_map, 247 | ARB_texture_cube_map_array, 248 | ARB_texture_env_add, 249 | ARB_texture_env_combine, 250 | ARB_texture_env_crossbar, 251 | ARB_texture_env_dot3, 252 | ARB_texture_filter_anisotropic, 253 | ARB_texture_filter_minmax, 254 | ARB_texture_float, 255 | ARB_texture_gather, 256 | ARB_texture_mirror_clamp_to_edge, 257 | ARB_texture_mirrored_repeat, 258 | ARB_texture_multisample, 259 | ARB_texture_non_power_of_two, 260 | ARB_texture_query_levels, 261 | ARB_texture_query_lod, 262 | ARB_texture_rectangle, 263 | ARB_texture_rg, 264 | ARB_texture_rgb10_a2ui, 265 | ARB_texture_stencil8, 266 | ARB_texture_storage, 267 | ARB_texture_storage_multisample, 268 | ARB_texture_swizzle, 269 | ARB_texture_view, 270 | ARB_timer_query, 271 | ARB_transform_feedback_instanced, 272 | ARB_transform_feedback_overflow_query, 273 | ARB_transform_feedback2, 274 | ARB_transform_feedback3, 275 | ARB_transpose_matrix, 276 | ARB_uniform_buffer_object, 277 | ARB_vertex_array_bgra, 278 | ARB_vertex_array_object, 279 | ARB_vertex_attrib_64bit, 280 | ARB_vertex_attrib_binding, 281 | ARB_vertex_blend, 282 | ARB_vertex_buffer_object, 283 | ARB_vertex_program, 284 | ARB_vertex_shader, 285 | ARB_vertex_type_2_10_10_10_rev, 286 | ARB_vertex_type_10f_11f_11f_rev, 287 | ARB_viewport_array, 288 | ARB_window_pos, 289 | ARM_mali_program_binary, 290 | ARM_mali_shader_binary, 291 | ARM_rgba8, 292 | ARM_shader_core_properties, 293 | ARM_shader_framebuffer_fetch, 294 | ARM_shader_framebuffer_fetch_depth_stencil, 295 | ARM_texture_unnormalized_coordinates, 296 | ATI_draw_buffers, 297 | ATI_element_array, 298 | ATI_envmap_bumpmap, 299 | ATI_fragment_shader, 300 | ATI_map_object_buffer, 301 | ATI_meminfo, 302 | ATI_pixel_format_float, 303 | ATI_pn_triangles, 304 | ATI_separate_stencil, 305 | ATI_text_fragment_shader, 306 | ATI_texture_env_combine3, 307 | ATI_texture_float, 308 | ATI_texture_mirror_once, 309 | ATI_vertex_array_object, 310 | ATI_vertex_attrib_array_object, 311 | ATI_vertex_streams, 312 | DMP_program_binary, 313 | DMP_shader_binary, 314 | EXT_422_pixels, 315 | EXT_EGL_image_array, 316 | EXT_EGL_image_storage, 317 | EXT_EGL_image_storage_compression, 318 | EXT_EGL_sync, 319 | EXT_YUV_target, 320 | EXT_abgr, 321 | EXT_base_instance, 322 | EXT_bgra, 323 | EXT_bindable_uniform, 324 | EXT_blend_color, 325 | EXT_blend_equation_separate, 326 | EXT_blend_func_extended, 327 | EXT_blend_func_separate, 328 | EXT_blend_logic_op, 329 | EXT_blend_minmax, 330 | EXT_blend_subtract, 331 | EXT_buffer_storage, 332 | EXT_clear_texture, 333 | EXT_clip_control, 334 | EXT_clip_cull_distance, 335 | EXT_clip_volume_hint, 336 | EXT_cmyka, 337 | EXT_color_buffer_float, 338 | EXT_color_buffer_half_float, 339 | EXT_color_subtable, 340 | EXT_compiled_vertex_array, 341 | EXT_conservative_depth, 342 | EXT_convolution, 343 | EXT_coordinate_frame, 344 | EXT_copy_image, 345 | EXT_copy_texture, 346 | EXT_cull_vertex, 347 | EXT_debug_label, 348 | EXT_debug_marker, 349 | EXT_depth_bounds_test, 350 | EXT_depth_clamp, 351 | EXT_direct_state_access, 352 | EXT_discard_framebuffer, 353 | EXT_disjoint_timer_query, 354 | EXT_draw_buffers, 355 | EXT_draw_buffers_indexed, 356 | EXT_draw_buffers2, 357 | EXT_draw_elements_base_vertex, 358 | EXT_draw_instanced, 359 | EXT_draw_range_elements, 360 | EXT_draw_transform_feedback, 361 | EXT_external_buffer, 362 | EXT_float_blend, 363 | EXT_fog_coord, 364 | EXT_fragment_shading_rate, 365 | EXT_framebuffer_blit, 366 | EXT_framebuffer_blit_layers, 367 | EXT_framebuffer_multisample, 368 | EXT_framebuffer_multisample_blit_scaled, 369 | EXT_framebuffer_object, 370 | EXT_framebuffer_sRGB, 371 | EXT_geometry_point_size, 372 | EXT_geometry_shader, 373 | EXT_geometry_shader4, 374 | EXT_gpu_program_parameters, 375 | EXT_gpu_shader4, 376 | EXT_gpu_shader5, 377 | EXT_histogram, 378 | EXT_index_array_formats, 379 | EXT_index_func, 380 | EXT_index_material, 381 | EXT_index_texture, 382 | EXT_instanced_arrays, 383 | EXT_light_texture, 384 | EXT_map_buffer_range, 385 | EXT_memory_object, 386 | EXT_memory_object_fd, 387 | EXT_memory_object_win32, 388 | EXT_misc_attribute, 389 | EXT_multi_draw_arrays, 390 | EXT_multi_draw_indirect, 391 | EXT_multisample, 392 | EXT_multisampled_compatibility, 393 | EXT_multisampled_render_to_texture, 394 | EXT_multisampled_render_to_texture2, 395 | EXT_multiview_draw_buffers, 396 | EXT_multiview_tessellation_geometry_shader, 397 | EXT_multiview_texture_multisample, 398 | EXT_multiview_timer_query, 399 | EXT_occlusion_query_boolean, 400 | EXT_packed_depth_stencil, 401 | EXT_packed_float, 402 | EXT_packed_pixels, 403 | EXT_paletted_texture, 404 | EXT_pixel_buffer_object, 405 | EXT_pixel_transform, 406 | EXT_pixel_transform_color_table, 407 | EXT_point_parameters, 408 | EXT_polygon_offset, 409 | EXT_polygon_offset_clamp, 410 | EXT_post_depth_coverage, 411 | EXT_primitive_bounding_box, 412 | EXT_protected_textures, 413 | EXT_provoking_vertex, 414 | EXT_pvrtc_sRGB, 415 | EXT_raster_multisample, 416 | EXT_read_format_bgra, 417 | EXT_render_snorm, 418 | EXT_rescale_normal, 419 | EXT_robustness, 420 | EXT_sRGB, 421 | EXT_sRGB_write_control, 422 | EXT_secondary_color, 423 | EXT_semaphore, 424 | EXT_semaphore_fd, 425 | EXT_semaphore_win32, 426 | EXT_separate_depth_stencil, 427 | EXT_separate_shader_objects, 428 | EXT_separate_specular_color, 429 | EXT_shader_framebuffer_fetch, 430 | EXT_shader_framebuffer_fetch_non_coherent, 431 | EXT_shader_group_vote, 432 | EXT_shader_image_load_formatted, 433 | EXT_shader_image_load_store, 434 | EXT_shader_implicit_conversions, 435 | EXT_shader_integer_mix, 436 | EXT_shader_io_blocks, 437 | EXT_shader_non_constant_global_initializers, 438 | EXT_shader_pixel_local_storage, 439 | EXT_shader_pixel_local_storage2, 440 | EXT_shader_samples_identical, 441 | EXT_shader_texture_lod, 442 | EXT_shadow_funcs, 443 | EXT_shadow_samplers, 444 | EXT_shared_texture_palette, 445 | EXT_sparse_texture, 446 | EXT_sparse_texture2, 447 | EXT_stencil_clear_tag, 448 | EXT_stencil_two_side, 449 | EXT_stencil_wrap, 450 | EXT_subtexture, 451 | EXT_tessellation_point_size, 452 | EXT_tessellation_shader, 453 | EXT_texture, 454 | EXT_texture_array, 455 | EXT_texture_border_clamp, 456 | EXT_texture_buffer, 457 | EXT_texture_buffer_object, 458 | EXT_texture_compression_astc_decode_mode, 459 | EXT_texture_compression_bptc, 460 | EXT_texture_compression_dxt1, 461 | EXT_texture_compression_latc, 462 | EXT_texture_compression_rgtc, 463 | EXT_texture_compression_s3tc, 464 | EXT_texture_compression_s3tc_srgb, 465 | EXT_texture_cube_map, 466 | EXT_texture_cube_map_array, 467 | EXT_texture_env_add, 468 | EXT_texture_env_combine, 469 | EXT_texture_env_dot3, 470 | EXT_texture_filter_anisotropic, 471 | EXT_texture_filter_minmax, 472 | EXT_texture_format_BGRA8888, 473 | EXT_texture_format_sRGB_override, 474 | EXT_texture_integer, 475 | EXT_texture_lod_bias, 476 | EXT_texture_mirror_clamp, 477 | EXT_texture_mirror_clamp_to_edge, 478 | EXT_texture_norm16, 479 | EXT_texture_object, 480 | EXT_texture_perturb_normal, 481 | EXT_texture_query_lod, 482 | EXT_texture_rg, 483 | EXT_texture_sRGB, 484 | EXT_texture_sRGB_R8, 485 | EXT_texture_sRGB_RG8, 486 | EXT_texture_sRGB_decode, 487 | EXT_texture_shadow_lod, 488 | EXT_texture_shared_exponent, 489 | EXT_texture_snorm, 490 | EXT_texture_storage, 491 | EXT_texture_storage_compression, 492 | EXT_texture_swizzle, 493 | EXT_texture_type_2_10_10_10_REV, 494 | EXT_texture_view, 495 | EXT_texture3D, 496 | EXT_timer_query, 497 | EXT_transform_feedback, 498 | EXT_unpack_subimage, 499 | EXT_vertex_array, 500 | EXT_vertex_array_bgra, 501 | EXT_vertex_attrib_64bit, 502 | EXT_vertex_shader, 503 | EXT_vertex_weighting, 504 | EXT_win32_keyed_mutex, 505 | EXT_window_rectangles, 506 | EXT_x11_sync_object, 507 | FJ_shader_binary_GCCSO, 508 | GREMEDY_frame_terminator, 509 | GREMEDY_string_marker, 510 | HP_convolution_border_modes, 511 | HP_image_transform, 512 | HP_occlusion_test, 513 | HP_texture_lighting, 514 | IBM_cull_vertex, 515 | IBM_multimode_draw_arrays, 516 | IBM_rasterpos_clip, 517 | IBM_static_data, 518 | IBM_texture_mirrored_repeat, 519 | IBM_vertex_array_lists, 520 | IMG_bindless_texture, 521 | IMG_framebuffer_downsample, 522 | IMG_multisampled_render_to_texture, 523 | IMG_program_binary, 524 | IMG_pvric_end_to_end_signature, 525 | IMG_read_format, 526 | IMG_shader_binary, 527 | IMG_texture_compression_pvrtc, 528 | IMG_texture_compression_pvrtc2, 529 | IMG_texture_env_enhanced_fixed_function, 530 | IMG_texture_filter_cubic, 531 | IMG_tile_region_protection, 532 | IMG_user_clip_plane, 533 | INGR_blend_func_separate, 534 | INGR_color_clamp, 535 | INGR_interlace_read, 536 | INTEL_blackhole_render, 537 | INTEL_conservative_rasterization, 538 | INTEL_fragment_shader_ordering, 539 | INTEL_framebuffer_CMAA, 540 | INTEL_map_texture, 541 | INTEL_parallel_arrays, 542 | INTEL_performance_query, 543 | KHR_blend_equation_advanced, 544 | KHR_blend_equation_advanced_coherent, 545 | KHR_context_flush_control, 546 | KHR_debug, 547 | KHR_no_error, 548 | KHR_parallel_shader_compile, 549 | KHR_robust_buffer_access_behavior, 550 | KHR_robustness, 551 | KHR_shader_subgroup, 552 | KHR_texture_compression_astc_hdr, 553 | KHR_texture_compression_astc_ldr, 554 | KHR_texture_compression_astc_sliced_3d, 555 | MESA_bgra, 556 | MESA_framebuffer_flip_x, 557 | MESA_framebuffer_flip_y, 558 | MESA_framebuffer_swap_xy, 559 | MESA_pack_invert, 560 | MESA_program_binary_formats, 561 | MESA_resize_buffers, 562 | MESA_sampler_objects, 563 | MESA_shader_integer_functions, 564 | MESA_tile_raster_order, 565 | MESA_window_pos, 566 | MESA_ycbcr_texture, 567 | MESAX_texture_stack, 568 | NV_alpha_to_coverage_dither_control, 569 | NV_bindless_multi_draw_indirect, 570 | NV_bindless_multi_draw_indirect_count, 571 | NV_bindless_texture, 572 | NV_blend_equation_advanced, 573 | NV_blend_equation_advanced_coherent, 574 | NV_blend_minmax_factor, 575 | NV_blend_square, 576 | NV_clip_space_w_scaling, 577 | NV_command_list, 578 | NV_compute_program5, 579 | NV_compute_shader_derivatives, 580 | NV_conditional_render, 581 | NV_conservative_raster, 582 | NV_conservative_raster_dilate, 583 | NV_conservative_raster_pre_snap, 584 | NV_conservative_raster_pre_snap_triangles, 585 | NV_conservative_raster_underestimation, 586 | NV_copy_buffer, 587 | NV_copy_depth_to_color, 588 | NV_copy_image, 589 | NV_coverage_sample, 590 | NV_deep_texture3D, 591 | NV_depth_buffer_float, 592 | NV_depth_clamp, 593 | NV_depth_nonlinear, 594 | NV_draw_buffers, 595 | NV_draw_instanced, 596 | NV_draw_texture, 597 | NV_draw_vulkan_image, 598 | NV_evaluators, 599 | NV_explicit_attrib_location, 600 | NV_explicit_multisample, 601 | NV_fbo_color_attachments, 602 | NV_fence, 603 | NV_fill_rectangle, 604 | NV_float_buffer, 605 | NV_fog_distance, 606 | NV_fragment_coverage_to_color, 607 | NV_fragment_program, 608 | NV_fragment_program_option, 609 | NV_fragment_program2, 610 | NV_fragment_program4, 611 | NV_fragment_shader_barycentric, 612 | NV_fragment_shader_interlock, 613 | NV_framebuffer_blit, 614 | NV_framebuffer_mixed_samples, 615 | NV_framebuffer_multisample, 616 | NV_framebuffer_multisample_coverage, 617 | NV_generate_mipmap_sRGB, 618 | NV_geometry_program4, 619 | NV_geometry_shader_passthrough, 620 | NV_geometry_shader4, 621 | NV_gpu_multicast, 622 | NV_gpu_program4, 623 | NV_gpu_program5, 624 | NV_gpu_program5_mem_extended, 625 | NV_gpu_shader5, 626 | NV_half_float, 627 | NV_image_formats, 628 | NV_instanced_arrays, 629 | NV_internalformat_sample_query, 630 | NV_light_max_exponent, 631 | NV_memory_attachment, 632 | NV_memory_object_sparse, 633 | NV_mesh_shader, 634 | NV_multisample_coverage, 635 | NV_multisample_filter_hint, 636 | NV_non_square_matrices, 637 | NV_occlusion_query, 638 | NV_pack_subimage, 639 | NV_packed_depth_stencil, 640 | NV_parameter_buffer_object, 641 | NV_parameter_buffer_object2, 642 | NV_path_rendering, 643 | NV_path_rendering_shared_edge, 644 | NV_pixel_buffer_object, 645 | NV_pixel_data_range, 646 | NV_point_sprite, 647 | NV_polygon_mode, 648 | NV_present_video, 649 | NV_primitive_restart, 650 | NV_primitive_shading_rate, 651 | NV_query_resource, 652 | NV_query_resource_tag, 653 | NV_read_buffer, 654 | NV_read_buffer_front, 655 | NV_read_depth, 656 | NV_read_depth_stencil, 657 | NV_read_stencil, 658 | NV_register_combiners, 659 | NV_register_combiners2, 660 | NV_representative_fragment_test, 661 | NV_robustness_video_memory_purge, 662 | NV_sRGB_formats, 663 | NV_sample_locations, 664 | NV_sample_mask_override_coverage, 665 | NV_scissor_exclusive, 666 | NV_shader_atomic_counters, 667 | NV_shader_atomic_float, 668 | NV_shader_atomic_float64, 669 | NV_shader_atomic_fp16_vector, 670 | NV_shader_atomic_int64, 671 | NV_shader_buffer_load, 672 | NV_shader_buffer_store, 673 | NV_shader_noperspective_interpolation, 674 | NV_shader_storage_buffer_object, 675 | NV_shader_subgroup_partitioned, 676 | NV_shader_texture_footprint, 677 | NV_shader_thread_group, 678 | NV_shader_thread_shuffle, 679 | NV_shading_rate_image, 680 | NV_shadow_samplers_array, 681 | NV_shadow_samplers_cube, 682 | NV_stereo_view_rendering, 683 | NV_tessellation_program5, 684 | NV_texgen_emboss, 685 | NV_texgen_reflection, 686 | NV_texture_barrier, 687 | NV_texture_border_clamp, 688 | NV_texture_compression_s3tc_update, 689 | NV_texture_compression_vtc, 690 | NV_texture_env_combine4, 691 | NV_texture_expand_normal, 692 | NV_texture_multisample, 693 | NV_texture_npot_2D_mipmap, 694 | NV_texture_rectangle, 695 | NV_texture_rectangle_compressed, 696 | NV_texture_shader, 697 | NV_texture_shader2, 698 | NV_texture_shader3, 699 | NV_timeline_semaphore, 700 | NV_transform_feedback, 701 | NV_transform_feedback2, 702 | NV_uniform_buffer_std430_layout, 703 | NV_uniform_buffer_unified_memory, 704 | NV_vdpau_interop, 705 | NV_vdpau_interop2, 706 | NV_vertex_array_range, 707 | NV_vertex_array_range2, 708 | NV_vertex_attrib_integer_64bit, 709 | NV_vertex_buffer_unified_memory, 710 | NV_vertex_program, 711 | NV_vertex_program1_1, 712 | NV_vertex_program2, 713 | NV_vertex_program2_option, 714 | NV_vertex_program3, 715 | NV_vertex_program4, 716 | NV_video_capture, 717 | NV_viewport_array, 718 | NV_viewport_array2, 719 | NV_viewport_swizzle, 720 | NVX_blend_equation_advanced_multi_draw_buffers, 721 | NVX_conditional_render, 722 | NVX_cross_process_interop, 723 | NVX_gpu_memory_info, 724 | NVX_gpu_multicast2, 725 | NVX_linked_gpu_multicast, 726 | NVX_progress_fence, 727 | OES_EGL_image, 728 | OES_EGL_image_external, 729 | OES_EGL_image_external_essl3, 730 | OES_blend_equation_separate, 731 | OES_blend_func_separate, 732 | OES_blend_subtract, 733 | OES_byte_coordinates, 734 | OES_compressed_ETC1_RGB8_sub_texture, 735 | OES_compressed_ETC1_RGB8_texture, 736 | OES_compressed_paletted_texture, 737 | OES_copy_image, 738 | OES_depth_texture, 739 | OES_depth24, 740 | OES_depth32, 741 | OES_draw_buffers_indexed, 742 | OES_draw_elements_base_vertex, 743 | OES_draw_texture, 744 | OES_element_index_uint, 745 | OES_extended_matrix_palette, 746 | OES_fbo_render_mipmap, 747 | OES_fixed_point, 748 | OES_fragment_precision_high, 749 | OES_framebuffer_object, 750 | OES_geometry_point_size, 751 | OES_geometry_shader, 752 | OES_get_program_binary, 753 | OES_gpu_shader5, 754 | OES_mapbuffer, 755 | OES_matrix_get, 756 | OES_matrix_palette, 757 | OES_packed_depth_stencil, 758 | OES_point_size_array, 759 | OES_point_sprite, 760 | OES_primitive_bounding_box, 761 | OES_query_matrix, 762 | OES_read_format, 763 | OES_required_internalformat, 764 | OES_rgb8_rgba8, 765 | OES_sample_shading, 766 | OES_sample_variables, 767 | OES_shader_image_atomic, 768 | OES_shader_io_blocks, 769 | OES_shader_multisample_interpolation, 770 | OES_single_precision, 771 | OES_standard_derivatives, 772 | OES_stencil_wrap, 773 | OES_stencil1, 774 | OES_stencil4, 775 | OES_stencil8, 776 | OES_surfaceless_context, 777 | OES_tessellation_point_size, 778 | OES_tessellation_shader, 779 | OES_texture_3D, 780 | OES_texture_border_clamp, 781 | OES_texture_buffer, 782 | OES_texture_compression_astc, 783 | OES_texture_cube_map, 784 | OES_texture_cube_map_array, 785 | OES_texture_env_crossbar, 786 | OES_texture_float, 787 | OES_texture_float_linear, 788 | OES_texture_half_float, 789 | OES_texture_half_float_linear, 790 | OES_texture_mirrored_repeat, 791 | OES_texture_npot, 792 | OES_texture_stencil8, 793 | OES_texture_storage_multisample_2d_array, 794 | OES_texture_view, 795 | OES_vertex_array_object, 796 | OES_vertex_half_float, 797 | OES_vertex_type_10_10_10_2, 798 | OES_viewport_array, 799 | OML_interlace, 800 | OML_resample, 801 | OML_subsample, 802 | OVR_multiview, 803 | OVR_multiview_multisampled_render_to_texture, 804 | OVR_multiview2, 805 | PGI_misc_hints, 806 | PGI_vertex_hints, 807 | QCOM_YUV_texture_gather, 808 | QCOM_alpha_test, 809 | QCOM_binning_control, 810 | QCOM_driver_control, 811 | QCOM_extended_get, 812 | QCOM_extended_get2, 813 | QCOM_frame_extrapolation, 814 | QCOM_framebuffer_foveated, 815 | QCOM_motion_estimation, 816 | QCOM_perfmon_global_mode, 817 | QCOM_render_sRGB_R8_RG8, 818 | QCOM_render_shared_exponent, 819 | QCOM_shader_framebuffer_fetch_noncoherent, 820 | QCOM_shader_framebuffer_fetch_rate, 821 | QCOM_shading_rate, 822 | QCOM_texture_foveated, 823 | QCOM_texture_foveated_subsampled_layout, 824 | QCOM_texture_foveated2, 825 | QCOM_texture_lod_bias, 826 | QCOM_tiled_rendering, 827 | QCOM_writeonly_rendering, 828 | QCOM_ycbcr_degamma, 829 | REND_screen_coordinates, 830 | S3_s3tc, 831 | SGI_color_matrix, 832 | SGI_color_table, 833 | SGI_texture_color_table, 834 | SGIS_detail_texture, 835 | SGIS_fog_function, 836 | SGIS_generate_mipmap, 837 | SGIS_multisample, 838 | SGIS_pixel_texture, 839 | SGIS_point_line_texgen, 840 | SGIS_point_parameters, 841 | SGIS_sharpen_texture, 842 | SGIS_texture_border_clamp, 843 | SGIS_texture_color_mask, 844 | SGIS_texture_edge_clamp, 845 | SGIS_texture_filter4, 846 | SGIS_texture_lod, 847 | SGIS_texture_select, 848 | SGIS_texture4D, 849 | SGIX_async, 850 | SGIX_async_histogram, 851 | SGIX_async_pixel, 852 | SGIX_blend_alpha_minmax, 853 | SGIX_calligraphic_fragment, 854 | SGIX_clipmap, 855 | SGIX_convolution_accuracy, 856 | SGIX_depth_pass_instrument, 857 | SGIX_depth_texture, 858 | SGIX_flush_raster, 859 | SGIX_fog_offset, 860 | SGIX_fragment_lighting, 861 | SGIX_framezoom, 862 | SGIX_igloo_interface, 863 | SGIX_instruments, 864 | SGIX_interlace, 865 | SGIX_ir_instrument1, 866 | SGIX_list_priority, 867 | SGIX_pixel_texture, 868 | SGIX_pixel_tiles, 869 | SGIX_polynomial_ffd, 870 | SGIX_reference_plane, 871 | SGIX_resample, 872 | SGIX_scalebias_hint, 873 | SGIX_shadow, 874 | SGIX_shadow_ambient, 875 | SGIX_sprite, 876 | SGIX_subsample, 877 | SGIX_tag_sample_buffer, 878 | SGIX_texture_add_env, 879 | SGIX_texture_coordinate_clamp, 880 | SGIX_texture_lod_bias, 881 | SGIX_texture_multi_buffer, 882 | SGIX_texture_scale_bias, 883 | SGIX_vertex_preclip, 884 | SGIX_ycrcb, 885 | SGIX_ycrcb_subsample, 886 | SGIX_ycrcba, 887 | SUN_convolution_border_modes, 888 | SUN_global_alpha, 889 | SUN_mesh_array, 890 | SUN_slice_accum, 891 | SUN_triangle_list, 892 | SUN_vertex, 893 | SUNX_constant_data, 894 | VIV_shader_binary, 895 | WIN_phong_shading, 896 | WIN_specular_fog, 897 | }; 898 | 899 | test { 900 | @import("std").testing.refAllDeclsRecursive(@This()); 901 | } 902 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | © 2013-2020 The Khronos Group Inc. 2 | © 2024 Carl Åstholm 3 | 4 | SPDX-License-Identifier: Apache-2.0 AND MIT 5 | 6 | --- 7 | 8 | Apache-2.0 license text: 9 | 10 | Apache License 11 | Version 2.0, January 2004 12 | http://www.apache.org/licenses/ 13 | 14 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 15 | 16 | 1. Definitions. 17 | 18 | "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. 19 | 20 | "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. 21 | 22 | "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. 27 | 28 | "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. 29 | 30 | "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). 31 | 32 | "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. 33 | 34 | "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." 35 | 36 | "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 37 | 38 | 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 39 | 40 | 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 41 | 42 | 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: 43 | 44 | (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and 45 | 46 | (b) You must cause any modified files to carry prominent notices stating that You changed the files; and 47 | 48 | (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and 49 | 50 | (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. 51 | 52 | You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 53 | 54 | 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 55 | 56 | 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 57 | 58 | 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 59 | 60 | 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 61 | 62 | 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. 63 | 64 | END OF TERMS AND CONDITIONS 65 | 66 | APPENDIX: How to apply the Apache License to your work. 67 | 68 | To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. 69 | 70 | Copyright [yyyy] [name of copyright owner] 71 | 72 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at 73 | 74 | http://www.apache.org/licenses/LICENSE-2.0 75 | 76 | Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. 77 | 78 | --- 79 | 80 | MIT license text: 81 | 82 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 83 | 84 | The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software. 85 | 86 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 87 | -------------------------------------------------------------------------------- /LICENSES/Apache-2.0.txt: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. 10 | 11 | "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. 12 | 13 | "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. 14 | 15 | "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. 16 | 17 | "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. 18 | 19 | "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. 20 | 21 | "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). 22 | 23 | "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. 24 | 25 | "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." 26 | 27 | "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 28 | 29 | 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 30 | 31 | 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 32 | 33 | 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: 34 | 35 | (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and 36 | 37 | (b) You must cause any modified files to carry prominent notices stating that You changed the files; and 38 | 39 | (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and 40 | 41 | (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. 42 | 43 | You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 44 | 45 | 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 46 | 47 | 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 48 | 49 | 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 50 | 51 | 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 52 | 53 | 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. 54 | 55 | END OF TERMS AND CONDITIONS 56 | 57 | APPENDIX: How to apply the Apache License to your work. 58 | 59 | To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. 60 | 61 | Copyright [yyyy] [name of copyright owner] 62 | 63 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at 64 | 65 | http://www.apache.org/licenses/LICENSE-2.0 66 | 67 | Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. 68 | -------------------------------------------------------------------------------- /LICENSES/MIT.txt: -------------------------------------------------------------------------------- 1 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 2 | 3 | The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software. 4 | 5 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 5 | 6 | # zigglgen 7 | 8 | The only Zig OpenGL binding generator you need. 9 | 10 | ## Installation and usage 11 | 12 | zigglgen currently supports the following versions of the Zig compiler: 13 | 14 | - `0.14.0` 15 | - `0.15.0-dev` (master) 16 | 17 | Older or more recent versions of the compiler are not guaranteed to be compatible. 18 | 19 | 1\. Run `zig fetch` to add the zigglgen package to your `build.zig.zon` manifest: 20 | 21 | ```sh 22 | zig fetch --save git+https://github.com/castholm/zigglgen.git 23 | ``` 24 | 25 | 2\. Generate a set of OpenGL bindings in your `build.zig` build script: 26 | 27 | ```zig 28 | const std = @import("std"); 29 | 30 | pub fn build(b: *std.Build) void { 31 | const exe_mod = b.createModule(...); 32 | 33 | // Choose the OpenGL API, version, profile and extensions you want to generate bindings for. 34 | const gl_bindings = @import("zigglgen").generateBindingsModule(b, .{ 35 | .api = .gl, 36 | .version = .@"4.1", 37 | .profile = .core, 38 | .extensions = &.{ .ARB_clip_control, .NV_scissor_exclusive }, 39 | }); 40 | 41 | // Import the generated module. 42 | exe_mod.addImport("gl", gl_bindings); 43 | } 44 | ``` 45 | 46 | 3\. Initialize OpenGL and start issuing commands: 47 | 48 | ```zig 49 | const windowing = @import(...); 50 | const gl = @import("gl"); 51 | 52 | // Procedure table that will hold OpenGL functions loaded at runtime. 53 | var procs: gl.ProcTable = undefined; 54 | 55 | pub fn main() !void { 56 | // Create an OpenGL context using a windowing system of your choice. 57 | const context = windowing.createContext(...); 58 | defer context.destroy(); 59 | 60 | // Make the OpenGL context current on the calling thread. 61 | windowing.makeContextCurrent(context); 62 | defer windowing.makeContextCurrent(null); 63 | 64 | // Initialize the procedure table. 65 | if (!procs.init(windowing.getProcAddress)) return error.InitFailed; 66 | 67 | // Make the procedure table current on the calling thread. 68 | gl.makeProcTableCurrent(&procs); 69 | defer gl.makeProcTableCurrent(null); 70 | 71 | // Issue OpenGL commands to your heart's content! 72 | const alpha: gl.float = 1; 73 | gl.ClearColor(1, 1, 1, alpha); 74 | gl.Clear(gl.COLOR_BUFFER_BIT); 75 | } 76 | ``` 77 | 78 | See [castholm/zig-examples](https://github.com/castholm/zig-examples) for example projects. 79 | 80 | ## API 81 | 82 | See [this gist](https://gist.github.com/castholm/a99b650cdd523244b456c7597e321e6e) for a preview of what the generated 83 | code might look like. 84 | 85 | ### OpenGL symbols 86 | 87 | zigglgen generates declarations for OpenGL functions, constants, types and extensions using the original names as 88 | defined in the various OpenGL specifications (as opposed to the prefixed names used in C). 89 | 90 | | | C | Zig | 91 | |-----------|:----------------------|:-------------------| 92 | | Command | `glClearColor` | `ClearColor` | 93 | | Constant | `GL_TRIANGLES` | `TRIANGLES` | 94 | | Type | `GLfloat` | `float` | 95 | | Extension | `GL_ARB_clip_control` | `ARB_clip_control` | 96 | 97 | ### `info` 98 | 99 | ```zig 100 | pub const info = struct {}; 101 | ``` 102 | 103 | Contains information about the generated set of OpenGL bindings, such as the OpenGL API, version and profile the 104 | bindings were generated for. 105 | 106 | ### `ProcTable` 107 | 108 | ```zig 109 | pub const ProcTable = struct {}; 110 | ``` 111 | 112 | Holds pointers to OpenGL functions loaded at runtime. 113 | 114 | This struct is very large, so you should avoid storing instances of it on the stack. Use global variables or allocate 115 | them on the heap instead. 116 | 117 | ### `ProcTable.init` 118 | 119 | ```zig 120 | pub fn init(procs: *ProcTable, loader: anytype) bool {} 121 | ``` 122 | 123 | Initializes the specified procedure table and returns `true` if successful, `false` otherwise. 124 | 125 | A procedure table must be successfully initialized before passing it to `makeProcTableCurrent` or accessing any of 126 | its fields. 127 | 128 | `loader` is duck-typed. Given the prefixed name of an OpenGL command (e.g. `"glClear"`), it should return a pointer to 129 | the corresponding function. It should be able to be used in one of the following two ways: 130 | 131 | - `@as(?PROC, loader(@as([*:0]const u8, prefixed_name)))` 132 | - `@as(?PROC, loader.getProcAddress(@as([*:0]const u8, prefixed_name)))` 133 | 134 | If your windowing system has a "get procedure address" function, it is usually enough to simply pass that function as 135 | the `loader` argument. 136 | 137 | No references to `loader` are retained after this function returns. 138 | 139 | There is no corresponding `deinit` function. 140 | 141 | ### `makeProcTableCurrent` 142 | 143 | ```zig 144 | pub fn makeProcTableCurrent(procs: ?*const ProcTable) void {} 145 | ``` 146 | 147 | Makes the specified procedure table current on the calling thread. 148 | 149 | A valid procedure table must be made current on a thread before issuing any OpenGL commands from that same thread. 150 | 151 | ### `getCurrentProcTable` 152 | 153 | ```zig 154 | pub fn getCurrentProcTable() ?*const ProcTable {} 155 | ``` 156 | 157 | Returns the procedure table that is current on the calling thread. 158 | 159 | ### `extensionSupported` 160 | 161 | (Only generated if at least one extension is specified.) 162 | 163 | ```zig 164 | pub fn extensionSupported(comptime extension: Extension) bool {} 165 | ``` 166 | 167 | Returns `true` if the specified OpenGL extension is supported by the procedure table that is current on the calling 168 | thread, `false` otherwise. 169 | 170 | ## FAQ 171 | 172 | ### Which OpenGL APIs are supported? 173 | 174 | Any APIs, versions, profiles and extensions included in Khronos's [OpenGL XML API 175 | Registry](https://github.com/KhronosGroup/OpenGL-Registry/tree/main/xml) are supported. These include: 176 | 177 | - OpenGL 1.0 through 3.1 178 | - OpenGL 3.2 through 4.6 (Compatibility/Core profile) 179 | - OpenGL ES 1.1 (Common/Common-Lite profile) 180 | - OpenGL ES 2.0 through 3.2 181 | - OpenGL SC 2.0 182 | 183 | The [`updateApiRegistry.ps1`](updateApiRegistry.ps1) PowerShell script is used to fetch the API registry and convert it 184 | to a set of Zig source files that are committed to revision control and used by zigglgen. 185 | 186 | ### Why is a thread-local procedure table required? 187 | 188 | Per the OpenGL spec, OpenGL function pointers loaded when one OpenGL context is current are not guaranteed to remain 189 | valid when a different context becomes current. This means that it would be incorrect to load a single set of function 190 | pointers to global memory just once at application startup and then have them be shared by all current and future 191 | OpenGL contexts. 192 | 193 | In order to support portable multi-threaded multi-context OpenGL applications, it must be possible to load multiple sets 194 | of function pointers. Because OpenGL contexts are already thread-local, it makes a lot of sense to handle function 195 | pointers in a similar manner. 196 | 197 | ### Why aren't OpenGL constants represented as Zig enums? 198 | 199 | The short answer is that it's simply not possible to represent groups of OpenGL constants as Zig enums in a 200 | satisfying manner: 201 | 202 | - The API registry currently specifies some of these groups, but far from all of them, and the groups are not guaranteed 203 | to be complete. Groups can be extended by extensions, so Zig enums would need to be defined as non-exhaustive, and 204 | using constants not specified as part of a group would require casting. 205 | - Some commands like *GetIntegerv* that can return constants will return them as plain integers. Comparing the returned 206 | values against Zig enum fields would require casting. 207 | - Some constants in the same group are aliases for the same value, which makes them impossible to represent as 208 | Zig enums. 209 | 210 | ### Why did calling a supported extension function result in a null pointer dereference? 211 | 212 | Certain OpenGL extension add features that are only conditionally available under certain OpenGL versions/profiles or 213 | when certain other extensions are also supported; for example, the *VertexWeighthNV* command from the *NV_half_float* 214 | extension is only available when the *EXT_vertex_weighting* extension is also supported. Unfortunately, the API registry 215 | does not specify these interactions in a consistent manner, so it's not possible for zigglgen to generate code that 216 | ensures that calls to supported extension functions are always safe. 217 | 218 | If you use OpenGL extensions it is your responsibility to read the extension specifications carefully and understand 219 | under which conditions their features are available. 220 | 221 | ### Why can't I pass my windowing system's `getProcAddress` function to `ProcTable.init`? 222 | 223 | It might have the wrong signature, such as taking a `[:0]const u8` (0-terminated slice) instead of a `[*:0]const u8` 224 | (0-terminated many-pointer), or returning a pointer without an alignment qualifier. To fix this, define your own 225 | function that wraps the windowing system's function and corrects the mismatch: 226 | 227 | ```zig 228 | fn fixedGetProcAddress(prefixed_name: [*:0]const u8) ?gl.PROC { 229 | return @alignCast(windowing.getProcAddress(std.mem.span(prefixed_name))); 230 | } 231 | 232 | // ... 233 | 234 | if (!gl_procs.init(fixedGetProcAddress)) return error.InitFailed; 235 | ``` 236 | 237 | ## Contributing 238 | 239 | If you have any issues or suggestions, please open an issue or a pull request. 240 | 241 | ### Help us define overrides for function parameters and return types! 242 | 243 | Due to the nature of the API Registry being designed for C, zigglgen currently generates most pointers types as `[*c]` 244 | pointers, which is less than ideal. A long-term goal for zigglgen is for every single pointer type to be correctly 245 | annotated. There are approximately 3300 commands defined in the API registry and if we work together, we can achieve 246 | that goal sooner. Even fixing up just a few commands would mean a lot! 247 | 248 | Overriding parameters/return types is very easy; all you need to do is add additional entries to the 249 | `paramOverride`/`returnTypeOverride` functions in [`zigglgen.zig`](zigglgen.zig), then open a pull request with your 250 | changes (bonus points if you also reference relevant OpenGL references page or specifications in the description of your 251 | pull request). 252 | 253 | ## License 254 | 255 | This repository is [REUSE-compliant](https://reuse.software/). The effective SPDX license expression for the repository as a whole is: 256 | 257 | ``` 258 | Apache-2.0 AND MIT 259 | ``` 260 | 261 | Copyright notices and license texts have been reproduced in [`LICENSE.txt`](LICENSE.txt), for your convenience. 262 | -------------------------------------------------------------------------------- /build.zig: -------------------------------------------------------------------------------- 1 | // © 2024 Carl Åstholm 2 | // SPDX-License-Identifier: MIT 3 | 4 | const std = @import("std"); 5 | 6 | pub fn build(b: *std.Build) void { 7 | const target = b.standardTargetOptions(.{}); 8 | const optimize = b.standardOptimizeOption(.{}); 9 | 10 | const zigglgen_exe = b.addExecutable(.{ 11 | .name = "zigglgen", 12 | .root_module = b.createModule(.{ 13 | .root_source_file = b.path("zigglgen.zig"), 14 | .target = target, 15 | .optimize = optimize, 16 | }), 17 | }); 18 | b.installArtifact(zigglgen_exe); 19 | 20 | const run_zigglgen = b.addRunArtifact(zigglgen_exe); 21 | run_zigglgen.addArgs(b.args orelse &.{}); 22 | run_zigglgen.step.dependOn(b.getInstallStep()); 23 | 24 | const run_step = b.step("run", "Run zigglgen"); 25 | run_step.dependOn(&run_zigglgen.step); 26 | 27 | const zigglgen_tests = b.addTest(.{ 28 | .root_source_file = generate_everything: { 29 | const r = b.addRunArtifact(zigglgen_exe); 30 | r.addArgs(&.{ "gl-4.6-core", "ZIGGLGEN_everything" }); 31 | const output = r.captureStdOut(); 32 | r.captured_stdout.?.basename = "gl.zig"; 33 | break :generate_everything output; 34 | }, 35 | .target = target, 36 | .optimize = optimize, 37 | }); 38 | 39 | const run_tests = b.addRunArtifact(zigglgen_tests); 40 | 41 | const test_step = b.step("test", "Sanity check zigglgen output"); 42 | test_step.dependOn(&run_tests.step); 43 | } 44 | 45 | pub const GeneratorOptions = @import("GeneratorOptions.zig"); 46 | 47 | pub fn generateBindingsModule(b: *std.Build, options: GeneratorOptions) *std.Build.Module { 48 | return b.createModule(.{ 49 | .root_source_file = generateBindingsSourceFile(b, options), 50 | }); 51 | } 52 | 53 | pub fn generateBindingsSourceFile(b: *std.Build, options: GeneratorOptions) std.Build.LazyPath { 54 | const zigglgen_dep = b.dependencyFromBuildZig(@This(), .{ 55 | .target = b.graph.host, 56 | .optimize = std.builtin.OptimizeMode.Debug, 57 | }); 58 | const zigglgen_exe = zigglgen_dep.artifact("zigglgen"); 59 | const run_zigglgen = b.addRunArtifact(zigglgen_exe); 60 | run_zigglgen.addArg(b.fmt("{s}-{s}{s}{s}", .{ 61 | @tagName(options.api), 62 | @tagName(options.version), 63 | if (options.profile != null) "-" else "", 64 | if (options.profile) |profile| @tagName(profile) else "", 65 | })); 66 | for (options.extensions) |extension| { 67 | run_zigglgen.addArg(@tagName(extension)); 68 | } 69 | const output = run_zigglgen.captureStdOut(); 70 | run_zigglgen.captured_stdout.?.basename = "gl.zig"; 71 | return output; 72 | } 73 | -------------------------------------------------------------------------------- /build.zig.zon: -------------------------------------------------------------------------------- 1 | // © 2024 Carl Åstholm 2 | // SPDX-License-Identifier: MIT 3 | 4 | .{ 5 | .name = .zigglgen, 6 | .version = "0.4.0", 7 | .fingerprint = 0xf697891b2daa6c6e, 8 | .minimum_zig_version = "0.14.0", 9 | .dependencies = .{}, 10 | .paths = .{ 11 | "GeneratorOptions.zig", 12 | "api_registry.zig", 13 | "build.zig", 14 | "build.zig.zon", 15 | "shims.zig", 16 | "zigglgen.zig", 17 | 18 | "LICENSES/", 19 | "LICENSE.txt", 20 | }, 21 | } 22 | -------------------------------------------------------------------------------- /updateApiRegistry.ps1: -------------------------------------------------------------------------------- 1 | # © 2024 Carl Åstholm 2 | # SPDX-License-Identifier: MIT 3 | 4 | #Requires -Version 7.4 5 | 6 | [CmdletBinding()] 7 | param () 8 | 9 | $ErrorActionPreference = 'Stop' 10 | Set-StrictMode -Off 11 | 12 | function main { 13 | $null = New-Item -ItemType Directory _OpenGL-Registry 14 | Push-Location _OpenGL-Registry 15 | try { 16 | try { 17 | git init 18 | git fetch https://github.com/KhronosGroup/OpenGL-Registry.git main 19 | git checkout FETCH_HEAD 20 | $registry = Select-Xml '/*' xml/gl.xml | Select-Object -ExpandProperty Node 21 | $rev = git rev-parse HEAD 22 | } finally { 23 | Pop-Location 24 | } 25 | 26 | # REUSE-IgnoreStart 27 | if ($registry.comment -notmatch '(?m)^Copyright 2013-2020 The Khronos Group Inc\.\r?\nSPDX-License-Identifier: Apache-2\.0$') { 28 | throw "The OpenGL XML API Registry license notice has changed." 29 | } 30 | # REUSE-IgnoreEnd 31 | 32 | processApiRegistry $registry $rev | zig fmt --stdin | Set-Content api_registry.zig 33 | zig test api_registry.zig 34 | 35 | processGeneratorOptions $registry $rev | zig fmt --stdin | Set-Content GeneratorOptions.zig 36 | zig test GeneratorOptions.zig 37 | } finally { 38 | Remove-Item _OpenGL-Registry -Recurse -Force 39 | } 40 | } 41 | 42 | function processApiRegistry ([System.Xml.XmlElement] $registry, [string] $rev) { 43 | # REUSE-IgnoreStart 44 | '// © 2013-2020 The Khronos Group Inc.' 45 | '// © 2024 Carl Åstholm' 46 | '// SPDX-License-Identifier: Apache-2.0 AND MIT' 47 | # REUSE-IgnoreEnd 48 | '' 49 | "// This file was generated by '$scriptName'." 50 | "// OpenGL XML API Registry revision: $rev" 51 | '' 52 | "pub const revision = `"$rev`";" 53 | '' 54 | 'pub const Type = struct {' 55 | ' name: Name,' 56 | ' requires: ?Name = null,' 57 | '' 58 | ' pub const Name = enum {' 59 | $registry 60 | | Select-Xml 'types/type' 61 | | Select-Object -ExpandProperty Node 62 | | Select-Object -ExpandProperty name 63 | | ForEach-Object { stripPrefix $_ } 64 | | Sort-Object { typeSortKey $_ } 65 | | ForEach-Object { "@`"$_`"," } 66 | ' };' 67 | '};' 68 | '' 69 | 'pub const Constant = struct {' 70 | ' name: Name,' 71 | ' value: i128,' 72 | ' api: ?Api.Name = null,' 73 | '' 74 | ' pub const Name = enum {' 75 | $registry 76 | | Select-Xml 'enums/enum' 77 | | Select-Object -ExpandProperty Node 78 | | Select-Object -ExpandProperty name -Unique 79 | | ForEach-Object { stripPrefix $_ } 80 | | Sort-Object { constantSortKey $_ } 81 | | ForEach-Object { "@`"$_`"," } 82 | ' };' 83 | '};' 84 | '' 85 | 'pub const Command = struct {' 86 | ' name: Name,' 87 | ' params: []const Param,' 88 | ' return_type_expr: []const Token,' 89 | '' 90 | ' pub const Name = enum {' 91 | $registry 92 | | Select-Xml 'commands/command/proto' 93 | | Select-Object -ExpandProperty Node 94 | | Select-Object -ExpandProperty name 95 | | ForEach-Object { stripPrefix $_ } 96 | | Sort-Object { commandSortKey $_ } 97 | | ForEach-Object { "@`"$_`"," } 98 | ' };' 99 | '' 100 | ' pub const Param = struct {' 101 | ' name: []const u8,' 102 | ' type_expr: []const Token,' 103 | ' };' 104 | '' 105 | ' pub const Token = union(enum) {' 106 | ' void,' 107 | ' @"*",' 108 | ' @"const",' 109 | ' type: Type.Name,' 110 | ' };' 111 | '};' 112 | '' 113 | 'pub const Api = struct {' 114 | ' name: Name,' 115 | ' version: [2]u8,' 116 | ' add: []const Feature,' 117 | ' remove: []const Feature,' 118 | '' 119 | ' pub const Name = enum { gl, gles1, gles2, glsc2 };' 120 | '};' 121 | '' 122 | 'pub const ProfileName = enum { core, compatibility, common, common_lite };' 123 | '' 124 | 'pub const Extension = struct {' 125 | ' name: Name,' 126 | ' apis: []const Api.Name,' 127 | ' add: []const Feature,' 128 | '' 129 | ' pub const Name = enum {' 130 | $registry 131 | | Select-Xml 'extensions/extension' 132 | | Select-Object -ExpandProperty Node 133 | | Select-Object -ExpandProperty name 134 | | ForEach-Object { stripPrefix $_ } 135 | | Sort-Object { extensionSortKey $_ } 136 | | ForEach-Object { "@`"$_`"," } 137 | ' };' 138 | '};' 139 | '' 140 | 'pub const Feature = struct {' 141 | ' name: Name,' 142 | ' api: ?Api.Name = null,' 143 | ' profile: ?ProfileName = null,' 144 | '' 145 | ' pub const Name = union(enum) {' 146 | ' type: Type.Name,' 147 | ' constant: Constant.Name,' 148 | ' command: Command.Name,' 149 | ' };' 150 | '};' 151 | '' 152 | 'pub const types = [_]Type{' 153 | $registry 154 | | Select-Xml 'types/type' 155 | | Select-Object -ExpandProperty Node 156 | | Sort-Object { typeSortKey (stripPrefix $_.name) } 157 | | ForEach-Object { 158 | '.{' 159 | ".name = .@`"$(stripPrefix $_.name)`"" 160 | if ($_.requires) { ", .requires = .@`"$(stripPrefix $_.requires)`"" } 161 | '},' 162 | } 163 | '};' 164 | '' 165 | 'pub const constants = [_]Constant{' 166 | $registry 167 | | Select-Xml 'enums/enum' 168 | | Select-Object -ExpandProperty Node 169 | | Sort-Object { constantSortKey (stripPrefix $_.name) }, api 170 | | ForEach-Object { 171 | '.{' 172 | ".name = .@`"$(stripPrefix $_.name)`"," 173 | ".value = $(+"$($_.value -replace '\A0x', '0x0')n")" 174 | if ($_.api) { ", .api = .$($_.api)" } 175 | '},' 176 | } 177 | '};' 178 | '' 179 | 'pub const commands = [_]Command{' 180 | $registry 181 | | Select-Xml 'commands/command' 182 | | Select-Object -ExpandProperty Node 183 | | Sort-Object { commandSortKey (stripPrefix $_.proto.name) } 184 | | ForEach-Object { 185 | '.{' 186 | ".name = .@`"$(stripPrefix $_.proto.name)`"," 187 | '.params = &.{' 188 | $_ 189 | | Select-Xml 'param' 190 | | Select-Object -ExpandProperty Node 191 | | ForEach-Object { 192 | '.{' 193 | ".name = `"$($_.name)`"," 194 | ".type_expr = &.{ $((parseDecl $_.InnerText) -join ', ') }" 195 | '},' 196 | } 197 | '},' 198 | ".return_type_expr = &.{ $((parseDecl $_.proto.InnerText) -join ', ') }," 199 | '},' 200 | } 201 | '};' 202 | '' 203 | 'pub const apis = [_]Api{' 204 | $registry 205 | | Select-Xml 'feature' 206 | | Select-Object -ExpandProperty Node 207 | | Sort-Object api, number 208 | | ForEach-Object { 209 | '.{' 210 | ".name = .$($_.api)," 211 | ".version = .{ $($_.number -split '\.' -join ', ') }," 212 | '.add = &.{' 213 | $_ 214 | | Select-Xml "require/*" 215 | | Select-Object -ExpandProperty Node 216 | | Sort-Object { 217 | switch ($_.LocalName) { 218 | 'type' { 0; break } 219 | 'enum' { 1; break } 220 | 'command' { 2; break } 221 | } 222 | }, { 223 | switch ($_.LocalName) { 224 | 'type' { typeSortKey (stripPrefix $_.name); break } 225 | 'enum' { constantSortKey (stripPrefix $_.name); break } 226 | 'command' { commandSortKey (stripPrefix $_.name); break } 227 | } 228 | } 229 | | ForEach-Object { 230 | '.{' 231 | ".name = .{ $( 232 | switch ($_.LocalName) { 233 | 'type' { '.type'; break } 234 | 'enum' { '.constant'; break } 235 | 'command' { '.command'; break } 236 | } 237 | ) = .@`"$(stripPrefix $_.name)`" }" 238 | if ($_.ParentNode.profile) { ", .profile = .$($_.ParentNode.profile -replace '-', '_')" } 239 | '},' 240 | } 241 | '},' 242 | '.remove = &.{' 243 | $_ 244 | | Select-Xml "remove/*" 245 | | Select-Object -ExpandProperty Node 246 | | Sort-Object { 247 | switch ($_.LocalName) { 248 | 'type' { 0; break } 249 | 'enum' { 1; break } 250 | 'command' { 2; break } 251 | } 252 | }, { 253 | switch ($_.LocalName) { 254 | 'type' { typeSortKey (stripPrefix $_.name); break } 255 | 'enum' { constantSortKey (stripPrefix $_.name); break } 256 | 'command' { commandSortKey (stripPrefix $_.name); break } 257 | } 258 | } 259 | | ForEach-Object { 260 | '.{' 261 | ".name = .{ $( 262 | switch ($_.LocalName) { 263 | 'type' { '.type'; break } 264 | 'enum' { '.constant'; break } 265 | 'command' { '.command'; break } 266 | } 267 | ) = .@`"$(stripPrefix $_.name)`" }" 268 | if ($_.ParentNode.profile) { ", .profile = .$($_.ParentNode.profile -replace '-', '_')" } 269 | '},' 270 | } 271 | '},' 272 | '},' 273 | } 274 | '};' 275 | '' 276 | 'pub const extensions = [_]Extension{' 277 | $registry 278 | | Select-Xml 'extensions/extension' 279 | | Select-Object -ExpandProperty Node 280 | | Sort-Object { extensionSortKey (stripPrefix $_.name) } 281 | | ForEach-Object { 282 | '.{' 283 | ".name = .@`"$(stripPrefix $_.name)`"," 284 | ".apis = &.{ $(($_.supported -split '\|' -match '\Agl(es[12]|sc2)?\z' -replace '\A.*\z', '.$&' -join ', ') | Sort-Object) }," 285 | '.add = &.{' 286 | $_ 287 | | Select-Xml "require/*" 288 | | Select-Object -ExpandProperty Node 289 | | Sort-Object { 290 | switch ($_.LocalName) { 291 | 'type' { 0; break } 292 | 'enum' { 1; break } 293 | 'command' { 2; break } 294 | } 295 | }, { 296 | switch ($_.LocalName) { 297 | 'type' { typeSortKey (stripPrefix $_.name); break } 298 | 'enum' { constantSortKey (stripPrefix $_.name); break } 299 | 'command' { commandSortKey (stripPrefix $_.name); break } 300 | } 301 | } 302 | | ForEach-Object { 303 | '.{' 304 | ".name = .{ $( 305 | switch ($_.LocalName) { 306 | 'type' { '.type'; break } 307 | 'enum' { '.constant'; break } 308 | 'command' { '.command'; break } 309 | } 310 | ) = .@`"$(stripPrefix $_.name)`" }" 311 | if ($_.ParentNode.api) { ", .api = .$($_.ParentNode.api)" } 312 | if ($_.ParentNode.profile) { ", .profile = .$($_.ParentNode.profile -replace '-', '_')" } 313 | '},' 314 | } 315 | '},' 316 | '},' 317 | } 318 | '};' 319 | '' 320 | 'test {' 321 | ' @import("std").testing.refAllDeclsRecursive(@This());' 322 | '}' 323 | } 324 | 325 | function processGeneratorOptions ([System.Xml.XmlElement] $registry, [string] $rev) { 326 | # REUSE-IgnoreStart 327 | '// © 2013-2020 The Khronos Group Inc.' 328 | '// © 2024 Carl Åstholm' 329 | '// SPDX-License-Identifier: Apache-2.0 AND MIT' 330 | # REUSE-IgnoreEnd 331 | '' 332 | "// This file was generated by '$scriptName'." 333 | "// OpenGL XML API Registry revision: $rev" 334 | '' 335 | 'api: Api,' 336 | 'version: Version,' 337 | 'profile: ?Profile = null,' 338 | 'extensions: []const Extension = &.{},' 339 | '' 340 | 'pub const Api = enum { gl, gles, glsc };' 341 | '' 342 | 'pub const Version = enum {' 343 | $registry 344 | | Select-Xml 'feature' 345 | | Select-Object -ExpandProperty Node 346 | | Select-Object -ExpandProperty number -Unique 347 | | Sort-Object 348 | | ForEach-Object { "@`"$_`"," } 349 | '};' 350 | '' 351 | 'pub const Profile = enum { core, compatibility, common, common_lite };' 352 | '' 353 | 'pub const Extension = enum {' 354 | $registry 355 | | Select-Xml 'extensions/extension' 356 | | Select-Object -ExpandProperty Node 357 | | Select-Object -ExpandProperty name 358 | | ForEach-Object { stripPrefix $_ } 359 | | Sort-Object { extensionSortKey $_ } 360 | | ForEach-Object { "@`"$_`"," } 361 | '};' 362 | '' 363 | 'test {' 364 | ' @import("std").testing.refAllDeclsRecursive(@This());' 365 | '}' 366 | } 367 | 368 | $scriptName = $PSCommandPath | Split-Path -Leaf 369 | 370 | function stripPrefix([string] $str) { 371 | $str -creplace '\A(GL_?|gl|struct\s+_*)', '' 372 | } 373 | 374 | function typeSortKey([string] $str) { 375 | $null = $str -cmatch @" 376 | (?x) 377 | \A 378 | (?.+?) 379 | (?3DFX|AMD|ANDROID|ANGLE|APPLE|ARB|ARM|ATI|DMP|EXT|FJ|GREMEDY|HP|IBM|IMG|INGR|INTEL|KHR|MESA|MESAX|NV|NVX|OES|OML|OVR|PGI|QCOM|REND|S3|SGI|SGIS|SGIX|SUN|SUNX|VIV|WIN)? 380 | \z 381 | "@ 382 | ( 383 | ( 384 | [regex]::Replace($Matches.base, '[0-9]+', { param ($m) $m.Value.PadLeft(5, '0') }) -csplit '(?<=[a-z])(?=[A-Z0-9])|(?<=[A-Z0-9])(?=[A-Z][a-z])' 385 | | ForEach-Object { basicSortKey $_ } 386 | ) -join '001' 387 | ) + "000$(basicSortKey $Matches.extension)" 388 | } 389 | 390 | function constantSortKey([string] $str) { 391 | $null = $str -cmatch @" 392 | (?x) 393 | \A 394 | (?.+?) 395 | (?:_(?3DFX|AMD|ANDROID|ANGLE|APPLE|ARB|ARM|ATI|DMP|EXT|FJ|GREMEDY|HP|IBM|IMG|INGR|INTEL|KHR|MESA|MESAX|NV|NVX|OES|OML|OVR|PGI|QCOM|REND|S3|SGI|SGIS|SGIX|SUN|SUNX|VIV|WIN))? 396 | \z 397 | "@ 398 | ( 399 | ( 400 | [regex]::Replace($Matches.base, '[0-9]+', { param ($m) $m.Value.PadLeft(5, '0') }) -split '_' 401 | | ForEach-Object { basicSortKey $_ } 402 | ) -join '001' 403 | ) + "000$(basicSortKey $Matches.extension)" 404 | } 405 | 406 | function commandSortKey ([string] $str) { 407 | $null = $str -cmatch @" 408 | (?x) 409 | \A 410 | (?.+?) 411 | (? 412 | b(? 427 | i(?3DFX|AMD|ANDROID|ANGLE|APPLE|ARB|ARM|ATI|DMP|EXT|FJ|GREMEDY|HP|IBM|IMG|INGR|INTEL|KHR|MESA|MESAX|NV|NVX|OES|OML|OVR|PGI|QCOM|REND|S3|SGI|SGIS|SGIX|SUN|SUNX|VIV|WIN)? 432 | \z 433 | "@ 434 | ( 435 | ( 436 | [regex]::Replace($Matches.base, '[0-9]+', { param ($m) $m.Value.PadLeft(5, '0') }) -split '_' 437 | | ForEach-Object { 438 | ( 439 | $_ -csplit '(?<=[a-z])(?=[A-Z0-9])|(?<=[A-Z0-9])(?=[A-Z][a-z])' 440 | | ForEach-Object { basicSortKey $_ } 441 | ) -join '004' 442 | } 443 | ) -join '003' 444 | ) + "000$(basicSortKey $Matches.type)001$(basicSortKey $Matches.array)002$(basicSortKey $Matches.extension)" 445 | } 446 | 447 | function extensionSortKey([string] $str) { 448 | ( 449 | [regex]::Replace($str, '[0-9]+', { param ($m) $m.Value.PadLeft(5, '0') }) -split '_' 450 | | ForEach-Object { basicSortKey $_ } 451 | ) -join '000' 452 | } 453 | 454 | function basicSortKey([string] $str) { 455 | (($str ?? '').GetEnumerator() | ForEach-Object { '{0:000}' -f ([ushort]$_ + 744) }) -join '' 456 | } 457 | 458 | function parseDecl ([string] $decl) { 459 | $tokens = 460 | $decl 461 | | Select-String '(struct\s+)?[^\s*]+|\*' -AllMatches 462 | | Select-Object -ExpandProperty Matches 463 | | Select-Object -ExpandProperty Value 464 | if ($tokens[0] -eq 'const') { 465 | $tokens[0], $tokens[1] = $tokens[1], $tokens[0] 466 | } 467 | $tokens[($tokens.Length - 2)..0] | ForEach-Object { 468 | if ($_ -in @('void'; '*'; 'const')) { 469 | ".@`"$_`"" 470 | } else { 471 | ".{ .type = .@`"$(stripPrefix $_)`" }" 472 | } 473 | } 474 | } 475 | 476 | Push-Location $PSScriptRoot 477 | try { main } finally { Pop-Location } 478 | -------------------------------------------------------------------------------- /zigglgen.zig: -------------------------------------------------------------------------------- 1 | // © 2024 Carl Åstholm 2 | // SPDX-License-Identifier: MIT 3 | 4 | const std = @import("std"); 5 | const builtin = @import("builtin"); 6 | 7 | const Options = @import("GeneratorOptions.zig"); 8 | const registry = @import("api_registry.zig"); 9 | 10 | /// Usage: `zigglen -[-] [ ...]` 11 | pub fn main() !void { 12 | var arena_state = std.heap.ArenaAllocator.init(std.heap.page_allocator); 13 | defer arena_state.deinit(); 14 | 15 | const arena = arena_state.allocator(); 16 | 17 | var arg_it = try std.process.argsWithAllocator(arena); 18 | 19 | const exe_name = arg_it.next() orelse "zigglen"; 20 | 21 | const raw_triple = arg_it.next() orelse printUsageAndExit(exe_name); 22 | const triple = ApiVersionProfile.parse(raw_triple) catch |err| 23 | return handleApiVersionProfileUserErrorAndExit(err, raw_triple); 24 | const api, const version, const profile = .{ triple.api, triple.version, triple.profile }; 25 | 26 | var extensions: ResolvedExtensions = .{}; 27 | var resolve_everything = false; 28 | while (arg_it.next()) |raw_extension| { 29 | if (std.mem.eql(u8, raw_extension, "ZIGGLGEN_everything")) { // For internal testing. 30 | resolve_everything = true; 31 | continue; 32 | } 33 | const extension = parseExtension(raw_extension, api) catch |err| 34 | return handleExtensionUserErrorAndExit(err, raw_extension, api, version, profile); 35 | extensions.put(extension, .{}); 36 | } 37 | 38 | var types: ResolvedTypes = .{}; 39 | var constants: ResolvedConstants = .{}; 40 | var commands: ResolvedCommands = .{}; 41 | if (resolve_everything) 42 | resolveEverything(&extensions, &types, &constants, &commands) 43 | else 44 | resolveQuery(api, version, profile, &extensions, &types, &constants, &commands); 45 | 46 | var stdout_state = std.io.bufferedWriter(std.io.getStdOut().writer()); 47 | const stdout = stdout_state.writer(); 48 | 49 | try renderCode(stdout, api, version, profile, &extensions, &types, &constants, &commands); 50 | 51 | try stdout_state.flush(); 52 | } 53 | 54 | const ApiVersionProfile = struct { 55 | api: registry.Api.Name, 56 | version: [2]u8, 57 | profile: ?registry.ProfileName, 58 | 59 | fn parse(raw: []const u8) ParseError!ApiVersionProfile { 60 | var raw_it = std.mem.splitScalar(u8, raw, '-'); 61 | const raw_api = raw_it.next().?; 62 | const raw_version = raw_it.next() orelse return error.MissingVersion; 63 | const maybe_raw_profile = raw_it.next(); 64 | if (raw_it.next() != null) return error.UnknownExtraField; 65 | 66 | var api: registry.Api.Name = switch (inline for (@typeInfo(Options.Api).@"enum".fields) |field| { 67 | if (std.mem.eql(u8, raw_api, field.name)) break @field(Options.Api, field.name); 68 | } else return error.InvalidApi) { 69 | .gl => .gl, 70 | .gles => .gles2, 71 | .glsc => .glsc2, 72 | }; 73 | 74 | const version: [2]u8 = inline for (@typeInfo(Options.Version).@"enum".fields) |field| { 75 | if (std.mem.eql(u8, raw_version, field.name)) { 76 | const dot = std.mem.indexOfScalar(u8, raw_version, '.').?; 77 | break .{ 78 | std.fmt.parseUnsigned(u8, raw_version[0..dot], 10) catch unreachable, 79 | std.fmt.parseUnsigned(u8, raw_version[(dot + 1)..], 10) catch unreachable, 80 | }; 81 | } 82 | } else return error.InvalidVersion; 83 | 84 | var maybe_profile: ?registry.ProfileName = if (maybe_raw_profile) |raw_profile| 85 | switch (inline for (@typeInfo(Options.Profile).@"enum".fields) |field| { 86 | if (std.mem.eql(u8, raw_profile, field.name)) break @field(Options.Profile, field.name); 87 | } else return error.InvalidProfile) { 88 | .core => .core, 89 | .compatibility => .compatibility, 90 | .common => .common, 91 | .common_lite => .common_lite, 92 | } 93 | else 94 | null; 95 | 96 | // Fix up API 97 | if (api == .gles2 and version[0] < 2) { 98 | api = .gles1; 99 | } 100 | 101 | // Validate version 102 | if (api == .gles1) { 103 | // GL ES 1.0/1.1 is an odd special case; the API Registry defines the feature set under 104 | // 1.0, but it includes features added in 1.1. Therefore, we only accept 1.1, even 105 | // though it's 1.0 in the registry. 106 | if (version[0] != 1 or version[1] != 1) return error.UnsupportedVersion; 107 | } else for (registry.apis) |reg_api| { 108 | if (reg_api.name == api and reg_api.version[0] == version[0] and reg_api.version[1] == version[1]) break; 109 | } else return error.UnsupportedVersion; 110 | 111 | // Validate/fix up profile 112 | switch (api) { 113 | .gl => { 114 | // The Core/Compatibility profiles were introduced in GL 3.2. 115 | if (version[0] < 3 or version[0] == 3 and version[1] < 2) { 116 | if (maybe_profile != null) return error.UnsupportedProfile; 117 | } else if (maybe_profile) |profile| switch (profile) { 118 | .core, .compatibility => {}, 119 | else => return error.UnsupportedProfile, 120 | } else { 121 | maybe_profile = .core; 122 | } 123 | }, 124 | .gles1 => { 125 | // The Common/Common-Lite profiles were introduced in GL ES 1.0. 126 | if (maybe_profile) |profile| switch (profile) { 127 | .common, .common_lite => {}, 128 | else => return error.UnsupportedProfile, 129 | } else { 130 | maybe_profile = .common; 131 | } 132 | }, 133 | // The Common/Common-Lite profiles were dropped in GL ES 2.0 (and GL SC never had any). 134 | else => if (maybe_profile != null) return error.UnsupportedProfile, 135 | } 136 | 137 | return .{ .api = api, .version = version, .profile = maybe_profile }; 138 | } 139 | 140 | const ParseError = error{ 141 | InvalidApi, 142 | MissingVersion, 143 | InvalidVersion, 144 | UnsupportedVersion, 145 | InvalidProfile, 146 | UnsupportedProfile, 147 | UnknownExtraField, 148 | }; 149 | }; 150 | 151 | fn parseExtension(raw: []const u8, api: registry.Api.Name) ParseExtensionError!registry.Extension.Name { 152 | // Statically assert that 'api_registry.zig' and 'GeneratorOptions.zig' are in sync. 153 | comptime { 154 | @setEvalBranchQuota(100_000); 155 | for (@typeInfo(registry.Extension.Name).@"enum".fields, @typeInfo(Options.Extension).@"enum".fields) |a, b| { 156 | std.debug.assert(std.mem.eql(u8, a.name, b.name)); 157 | } 158 | } 159 | 160 | const extension: registry.Extension.Name = inline for (@typeInfo(registry.Extension.Name).@"enum".fields) |field| { 161 | if (std.mem.eql(u8, raw, field.name)) break @field(registry.Extension.Name, field.name); 162 | } else return error.InvalidExtension; 163 | 164 | // Validate extension 165 | const reg_extension = for (registry.extensions) |reg_extension| { 166 | if (reg_extension.name == extension) break reg_extension; 167 | } else return error.UnsupportedExtension; 168 | if (std.mem.indexOfScalar(registry.Api.Name, reg_extension.apis, api) == null) return error.UnsupportedExtension; 169 | 170 | return extension; 171 | } 172 | 173 | const ParseExtensionError = error{ 174 | InvalidExtension, 175 | UnsupportedExtension, 176 | }; 177 | 178 | fn printUsageAndExit(exe_name: []const u8) noreturn { 179 | std.debug.print("Usage: {s} -[-] [ ...]", .{std.fs.path.basename(exe_name)}); 180 | std.process.exit(1); 181 | } 182 | 183 | fn handleApiVersionProfileUserErrorAndExit( 184 | err: ApiVersionProfile.ParseError, 185 | raw_triple: []const u8, 186 | ) noreturn { 187 | var raw_it = std.mem.splitScalar(u8, raw_triple, '-'); 188 | const raw_api = raw_it.next().?; 189 | const raw_version = raw_it.next(); 190 | const raw_profile = raw_it.next(); 191 | const raw_extra = raw_it.next(); 192 | switch (err) { 193 | error.InvalidApi, 194 | => std.log.err("API '{s}' is not a supported API", .{raw_api}), 195 | error.MissingVersion, 196 | => std.log.err("missing version field after API field", .{}), 197 | error.InvalidVersion, 198 | error.UnsupportedVersion, 199 | => std.log.err("version '{s}' is not a supported version of '{s}'", .{ raw_version.?, raw_api }), 200 | error.InvalidProfile, 201 | error.UnsupportedProfile, 202 | => std.log.err("profile '{s}' is not a supported profile of '{s}-{s}'", .{ raw_profile.?, raw_api, raw_version.? }), 203 | error.UnknownExtraField, 204 | => std.log.err("unknown extra value '{s}' after profile field", .{raw_extra.?}), 205 | } 206 | std.process.exit(1); 207 | } 208 | 209 | fn handleExtensionUserErrorAndExit( 210 | err: ParseExtensionError, 211 | raw_extension: []const u8, 212 | api: registry.Api.Name, 213 | version: [2]u8, 214 | profile: ?registry.ProfileName, 215 | ) noreturn { 216 | switch (err) { 217 | error.InvalidExtension, 218 | error.UnsupportedExtension, 219 | => std.log.err("extension '{s}' is not a supported extension of '{s}-{}.{}{s}{s}'", .{ 220 | raw_extension, 221 | @tagName(api), 222 | version[0], 223 | version[1], 224 | if (profile != null) "-" else "", 225 | if (profile) |x| @tagName(x) else "", 226 | }), 227 | } 228 | std.process.exit(1); 229 | } 230 | 231 | comptime { 232 | @setEvalBranchQuota(100_000); 233 | _ = std.enums.EnumIndexer(registry.Extension.Name); 234 | _ = std.enums.EnumIndexer(registry.Type.Name); 235 | _ = std.enums.EnumIndexer(registry.Constant.Name); 236 | _ = std.enums.EnumIndexer(registry.Command.Name); 237 | } 238 | 239 | const ResolvedExtensions = std.EnumMap(registry.Extension.Name, struct { 240 | commands: std.EnumSet(registry.Command.Name) = .{}, 241 | }); 242 | 243 | const ResolvedTypes = std.EnumMap(registry.Type.Name, struct { 244 | requires: ?registry.Type.Name = null, 245 | }); 246 | 247 | const ResolvedConstants = std.EnumMap(registry.Constant.Name, struct { 248 | value: i128, 249 | }); 250 | 251 | const ResolvedCommands = std.EnumMap(registry.Command.Name, struct { 252 | params: []const registry.Command.Param, 253 | return_type_expr: []const registry.Command.Token, 254 | required: bool = false, 255 | }); 256 | 257 | fn resolveQuery( 258 | api: registry.Api.Name, 259 | version: [2]u8, 260 | profile: ?registry.ProfileName, 261 | extensions: *ResolvedExtensions, 262 | types: *ResolvedTypes, 263 | constants: *ResolvedConstants, 264 | commands: *ResolvedCommands, 265 | ) void { 266 | // Add/remove API features 267 | for (registry.apis) |reg_api| { 268 | if (reg_api.name != api) continue; 269 | if (reg_api.version[0] > version[0] or reg_api.version[0] == version[0] and reg_api.version[1] > version[1]) continue; 270 | for (reg_api.remove) |feature| { 271 | std.debug.assert(feature.api == null); 272 | if (feature.profile != null and feature.profile != profile) continue; 273 | switch (feature.name) { 274 | .type => |name| types.remove(name), 275 | .constant => |name| constants.remove(name), 276 | .command => |name| commands.remove(name), 277 | } 278 | } 279 | for (reg_api.add) |feature| { 280 | std.debug.assert(feature.api == null); 281 | if (feature.profile != null and feature.profile != profile) continue; 282 | switch (feature.name) { 283 | .type => |name| _ = tryPutType(types, name), 284 | .constant => |name| _ = tryPutConstant(constants, name, api), 285 | .command => |name| _ = tryPutCommand(commands, name, true), 286 | } 287 | } 288 | } 289 | 290 | // Add extension features 291 | var extension_it = extensions.iterator(); 292 | while (extension_it.next()) |extension| { 293 | for (registry.extensions) |reg_extension| { 294 | if (reg_extension.name != extension.key) continue; 295 | std.debug.assert(std.mem.indexOfScalar(registry.Api.Name, reg_extension.apis, api) != null); 296 | for (reg_extension.add) |feature| { 297 | if (feature.api != null and feature.api != api) continue; 298 | if (feature.profile != null and feature.profile != profile) continue; 299 | switch (feature.name) { 300 | .type => |name| _ = tryPutType(types, name), 301 | .constant => |name| _ = tryPutConstant(constants, name, api), 302 | .command => |name| { 303 | _ = tryPutCommand(commands, name, false); 304 | extension.value.commands.insert(name); 305 | }, 306 | } 307 | } 308 | break; 309 | } 310 | } 311 | 312 | // Add command type dependencies 313 | var command_it = commands.iterator(); 314 | while (command_it.next()) |command| { 315 | for (command.value.params) |param| for (param.type_expr) |token| switch (token) { 316 | .type => |name| _ = tryPutType(types, name), 317 | else => {}, 318 | }; 319 | for (command.value.return_type_expr) |token| switch (token) { 320 | .type => |name| _ = tryPutType(types, name), 321 | else => {}, 322 | }; 323 | } 324 | 325 | // Add type type dependencies 326 | while (true) { 327 | var mutated = false; 328 | var type_it = types.iterator(); 329 | while (type_it.next()) |@"type"| { 330 | if (@"type".value.requires) |requires| if (tryPutType(types, requires)) { 331 | mutated = true; 332 | }; 333 | } 334 | if (!mutated) break; 335 | } 336 | } 337 | 338 | fn tryPutType(types: *ResolvedTypes, name: registry.Type.Name) bool { 339 | if (types.contains(name)) return false; 340 | for (registry.types) |reg_type| { 341 | if (reg_type.name != name) continue; 342 | types.put(name, .{ .requires = reg_type.requires }); 343 | return true; 344 | } 345 | unreachable; 346 | } 347 | 348 | fn tryPutConstant(constants: *ResolvedConstants, name: registry.Constant.Name, api: registry.Api.Name) bool { 349 | if (constants.contains(name)) return false; 350 | for (registry.constants) |reg_constant| { 351 | if (reg_constant.name != name) continue; 352 | if (reg_constant.api != null and reg_constant.api != api) continue; 353 | constants.put(name, .{ .value = reg_constant.value }); 354 | return true; 355 | } 356 | unreachable; 357 | } 358 | 359 | fn tryPutCommand(commands: *ResolvedCommands, name: registry.Command.Name, required: bool) bool { 360 | if (commands.contains(name)) return false; 361 | for (registry.commands) |reg_command| { 362 | if (reg_command.name != name) continue; 363 | commands.put(name, .{ 364 | .params = reg_command.params, 365 | .return_type_expr = reg_command.return_type_expr, 366 | .required = required, 367 | }); 368 | return true; 369 | } 370 | unreachable; 371 | } 372 | 373 | fn resolveEverything( 374 | extensions: *ResolvedExtensions, 375 | types: *ResolvedTypes, 376 | constants: *ResolvedConstants, 377 | commands: *ResolvedCommands, 378 | ) void { 379 | @setEvalBranchQuota(100_000); 380 | for (std.enums.values(registry.Extension.Name)) |name| extensions.put(name, .{}); 381 | for (std.enums.values(registry.Type.Name)) |name| _ = tryPutType(types, name); 382 | for (std.enums.values(registry.Constant.Name)) |name| _ = tryPutConstant(constants, name, .gl); 383 | for (std.enums.values(registry.Command.Name)) |name| _ = tryPutCommand(commands, name, false); 384 | } 385 | 386 | fn renderCode( 387 | writer: anytype, 388 | api: registry.Api.Name, 389 | version: [2]u8, 390 | profile: ?registry.ProfileName, 391 | extensions: *ResolvedExtensions, 392 | types: *ResolvedTypes, 393 | constants: *ResolvedConstants, 394 | commands: *ResolvedCommands, 395 | ) !void { 396 | const any_extensions = extensions.count() != 0; 397 | 398 | try writer.print("" ++ 399 | // REUSE-IgnoreStart 400 | \\// © 2013-2020 The Khronos Group Inc. 401 | \\// © 2024 Carl Åstholm 402 | \\// SPDX-License-Identifier: Apache-2.0 AND MIT 403 | // REUSE-IgnoreEnd 404 | \\ 405 | \\//! Bindings for {[api_pretty]s} {[version_major]d}.{[version_minor]d}{[sp_profile_pretty]s} generated by zigglgen. 406 | \\ 407 | \\// OpenGL XML API Registry revision: {[registry_revision]s} 408 | \\// zigglgen version: 0.4.0 409 | \\ 410 | \\// Example usage: 411 | \\// 412 | \\// const windowing = @import(...); 413 | \\// const gl = @import("gl"); 414 | \\// 415 | \\// // Procedure table that will hold OpenGL functions loaded at runtime. 416 | \\// var procs: gl.ProcTable = undefined; 417 | \\// 418 | \\// pub fn main() !void {{ 419 | \\// // Create an OpenGL context using a windowing system of your choice. 420 | \\// const context = windowing.createContext(...); 421 | \\// defer context.destroy(); 422 | \\// 423 | \\// // Make the OpenGL context current on the calling thread. 424 | \\// windowing.makeContextCurrent(context); 425 | \\// defer windowing.makeContextCurrent(null); 426 | \\// 427 | \\// // Initialize the procedure table. 428 | \\// if (!procs.init(windowing.getProcAddress)) return error.InitFailed; 429 | \\// 430 | \\// // Make the procedure table current on the calling thread. 431 | \\// gl.makeProcTableCurrent(&procs); 432 | \\// defer gl.makeProcTableCurrent(null); 433 | \\// 434 | \\// // Issue OpenGL commands to your heart's content! 435 | \\// const alpha: gl.{[clear_color_type]s} = 1; 436 | \\// gl.{[clear_color_fn]s}(1, 1, 1, alpha); 437 | \\// gl.Clear(gl.COLOR_BUFFER_BIT); 438 | \\// }} 439 | \\// 440 | \\ 441 | \\const std = @import("std"); 442 | \\const builtin = @import("builtin"); 443 | \\ 444 | \\/// Information about this set of OpenGL bindings. 445 | \\pub const info = struct {{ 446 | \\ pub const api: Api = {[api]s}; 447 | \\ pub const version_major = {[version_major]d}; 448 | \\ pub const version_minor = {[version_minor]d}; 449 | \\ pub const profile: ?Profile = {[profile]s}; 450 | \\ 451 | \\ pub const Api = enum {{ gl, gles, glsc }}; 452 | \\ pub const Profile = enum {{ core, compatibility, common, common_lite }}; 453 | \\}}; 454 | \\ 455 | , .{ 456 | .registry_revision = registry.revision, 457 | .api_pretty = switch (api) { 458 | .gl => "OpenGL", 459 | .gles1, .gles2 => "OpenGL ES", 460 | .glsc2 => "OpenGL SC", 461 | }, 462 | .api = switch (api) { 463 | .gl => ".gl", 464 | .gles1, .gles2 => ".gles", 465 | .glsc2 => ".glsc", 466 | }, 467 | .version_major = version[0], 468 | .version_minor = version[1], 469 | .sp_profile_pretty = if (profile) |x| switch (x) { 470 | .core => " (Core profile)", 471 | .compatibility => " (Compatibility profile)", 472 | .common => " (Common profile)", 473 | .common_lite => " (Common-Lite profile)", 474 | } else "", 475 | .profile = if (profile) |x| switch (x) { 476 | .core => ".core", 477 | .compatibility => ".compatibility", 478 | .common => ".common", 479 | .common_lite => ".common_lite", 480 | } else "null", 481 | .clear_color_type = if (profile == .common_lite) "fixed" else "float", 482 | .clear_color_fn = if (profile == .common_lite) "ClearColorx" else "ClearColor", 483 | }); 484 | try writer.writeAll( 485 | \\ 486 | \\/// Makes the specified procedure table current on the calling thread. 487 | \\/// 488 | \\/// A valid procedure table must be made current on a thread before issuing any OpenGL commands from 489 | \\/// that same thread. 490 | \\pub fn makeProcTableCurrent(procs: ?*const ProcTable) void { 491 | \\ ProcTable.current = procs; 492 | \\} 493 | \\ 494 | \\/// Returns the procedure table that is current on the calling thread. 495 | \\pub fn getCurrentProcTable() ?*const ProcTable { 496 | \\ return ProcTable.current; 497 | \\} 498 | \\ 499 | ); 500 | if (any_extensions) { 501 | try writer.writeAll( 502 | \\ 503 | \\/// Returns `true` if the specified OpenGL extension is supported by the procedure table that is 504 | \\/// current on the calling thread, `false` otherwise. 505 | \\pub fn extensionSupported(comptime extension: Extension) bool { 506 | \\ return @field(ProcTable.current orelse return false, @tagName(extension)); 507 | \\} 508 | \\ 509 | \\/// OpenGL extension. 510 | \\pub const Extension = enum { 511 | \\ 512 | ); 513 | var extension_it = extensions.iterator(); 514 | while (extension_it.next()) |extension| { 515 | try writer.print( 516 | \\ {p}, 517 | \\ 518 | , .{std.zig.fmtId(@tagName(extension.key))}); 519 | } 520 | try writer.writeAll( 521 | \\}; 522 | \\ 523 | ); 524 | } 525 | try writer.writeAll( 526 | \\ 527 | \\pub const APIENTRY = if (builtin.os.tag == .windows and builtin.cpu.arch == .x86) std.builtin.CallingConvention.Stdcall else std.builtin.CallingConvention.C; 528 | \\pub const PROC = *align(@alignOf(fn () callconv(APIENTRY) void)) const anyopaque; 529 | \\ 530 | \\//#region Types 531 | \\ 532 | ); 533 | var type_it = types.iterator(); 534 | while (type_it.next()) |@"type"| { 535 | switch (@"type".key) { 536 | .khrplatform, .void => continue, 537 | else => {}, 538 | } 539 | try writer.print( 540 | \\pub const {} = {s}; 541 | \\ 542 | , .{ std.zig.fmtId(@tagName(@"type".key)), getTypeValue(@"type".key) }); 543 | } 544 | try writer.writeAll( 545 | \\//#endregion Types 546 | \\ 547 | \\//#region Constants 548 | \\ 549 | ); 550 | var constant_it = constants.iterator(); 551 | while (constant_it.next()) |constant| { 552 | try writer.print( 553 | \\pub const {} = {s}0x{X}; 554 | \\ 555 | , .{ std.zig.fmtId(@tagName(constant.key)), if (constant.value.value < 0) "-" else "", @abs(constant.value.value) }); 556 | } 557 | try writer.writeAll( 558 | \\//#endregion Constants 559 | \\ 560 | \\//#region Commands 561 | \\ 562 | ); 563 | var command_it = commands.iterator(); 564 | while (command_it.next()) |command| { 565 | try writer.print("pub fn {}(", .{std.zig.fmtId(@tagName(command.key))}); 566 | try renderParams(writer, command, false); 567 | try writer.writeAll(") callconv(APIENTRY) "); 568 | try renderReturnType(writer, command); 569 | try writer.print(" {{\n return ProcTable.current.?.{p_}", .{std.zig.fmtId(@tagName(command.key))}); 570 | if (!command.value.required) try writer.writeAll(".?"); 571 | try writer.writeAll("("); 572 | try renderParams(writer, command, true); 573 | try writer.writeAll(");\n}\n"); 574 | } 575 | try writer.writeAll( 576 | \\//#endregion Commands 577 | \\ 578 | \\/// Holds OpenGL features loaded at runtime. 579 | \\/// 580 | \\/// This struct is very large; avoid storing instances of it on the stack. 581 | \\pub const ProcTable = struct { 582 | \\ threadlocal var current: ?*const ProcTable = null; 583 | \\ 584 | \\ //#region Fields 585 | \\ 586 | ); 587 | if (any_extensions) { 588 | var extension_it = extensions.iterator(); 589 | while (extension_it.next()) |extension| { 590 | try writer.print( 591 | \\ {p_}: bool, 592 | \\ 593 | , .{std.zig.fmtId(@tagName(extension.key))}); 594 | } 595 | } 596 | command_it = commands.iterator(); 597 | while (command_it.next()) |command| { 598 | try writer.print(" {p_}: ", .{std.zig.fmtId(@tagName(command.key))}); 599 | if (!command.value.required) try writer.writeAll("?"); 600 | try writer.writeAll("*const fn ("); 601 | try renderParams(writer, command, false); 602 | try writer.writeAll(") callconv(APIENTRY) "); 603 | try renderReturnType(writer, command); 604 | try writer.writeAll(",\n"); 605 | } 606 | try writer.writeAll( 607 | \\ //#endregion Fields 608 | \\ 609 | \\ /// Initializes the specified procedure table and returns `true` if successful, 610 | \\ /// `false` otherwise. 611 | \\ /// 612 | \\ /// A procedure table must be successfully initialized before passing it to 613 | \\ /// `makeProcTableCurrent` or accessing any of its fields. 614 | \\ /// 615 | \\ /// `loader` is duck-typed. Given the prefixed name of an OpenGL command (e.g. `"glClear"`), it 616 | \\ /// should return a pointer to the corresponding function. It should be able to be used in one 617 | \\ /// of the following two ways: 618 | \\ /// 619 | \\ /// - `@as(?PROC, loader(@as([*:0]const u8, prefixed_name)))` 620 | \\ /// - `@as(?PROC, loader.getProcAddress(@as([*:0]const u8, prefixed_name)))` 621 | \\ /// 622 | \\ /// If your windowing system has a "get procedure address" function, it is usually enough to 623 | \\ /// simply pass that function as the `loader` argument. 624 | \\ /// 625 | \\ /// No references to `loader` are retained after this function returns. 626 | \\ /// 627 | \\ /// There is no corresponding `deinit` function. 628 | \\ pub fn init(procs: *ProcTable, loader: anytype) bool { 629 | \\ @setEvalBranchQuota(1_000_000); 630 | \\ var success: u1 = 1; 631 | \\ inline for (@typeInfo(ProcTable).@"struct".fields) |field_info| { 632 | \\ switch (@typeInfo(field_info.type)) { 633 | \\ .pointer => |ptr_info| switch (@typeInfo(ptr_info.child)) { 634 | \\ .@"fn" => { 635 | \\ success &= @intFromBool(procs.initCommand(loader, field_info.name)); 636 | \\ }, 637 | \\ else => comptime unreachable, 638 | \\ }, 639 | \\ 640 | ); 641 | if (any_extensions) { 642 | try writer.writeAll( 643 | \\ .optional => |opt_info| switch (@typeInfo(opt_info.child)) { 644 | \\ .pointer => |ptr_info| switch (@typeInfo(ptr_info.child)) { 645 | \\ .@"fn" => { 646 | \\ @field(procs, field_info.name) = null; 647 | \\ }, 648 | \\ else => comptime unreachable, 649 | \\ }, 650 | \\ else => comptime unreachable, 651 | \\ }, 652 | \\ .bool => { 653 | \\ @field(procs, field_info.name) = false; 654 | \\ }, 655 | \\ 656 | ); 657 | } 658 | try writer.writeAll( 659 | \\ else => comptime unreachable, 660 | \\ } 661 | \\ } 662 | \\ 663 | ); 664 | if (any_extensions) { 665 | try writer.writeAll( 666 | \\ if (success == 0) return false; 667 | \\ 668 | ); 669 | var extension_it = extensions.iterator(); 670 | while (extension_it.next()) |extension| { 671 | if (extension.value.commands.count() != 0) { 672 | try writer.print( 673 | \\ if (procs.initExtension("{s}")) {{ 674 | \\ 675 | , .{@tagName(extension.key)}); 676 | var extension_command_it = extension.value.commands.iterator(); 677 | while (extension_command_it.next()) |extension_command| { 678 | try writer.print( 679 | \\ _ = procs.initCommand(loader, "{s}"); 680 | \\ 681 | , .{@tagName(extension_command)}); 682 | } 683 | try writer.writeAll( 684 | \\ } 685 | \\ 686 | ); 687 | } else { 688 | try writer.print( 689 | \\ _ = procs.initExtension("{s}"); 690 | \\ 691 | , .{@tagName(extension.key)}); 692 | } 693 | } 694 | try writer.writeAll( 695 | \\ return true; 696 | \\ 697 | ); 698 | } else { 699 | try writer.writeAll( 700 | \\ return success != 0; 701 | \\ 702 | ); 703 | } 704 | try writer.writeAll( 705 | \\ } 706 | \\ 707 | \\ fn initCommand(procs: *ProcTable, loader: anytype, comptime name: [:0]const u8) bool { 708 | \\ if (getProcAddress(loader, "gl" ++ name)) |proc| { 709 | \\ @field(procs, name) = @ptrCast(proc); 710 | \\ return true; 711 | \\ } else { 712 | \\ return @typeInfo(@TypeOf(@field(procs, name))) == .optional; 713 | \\ } 714 | \\ } 715 | \\ 716 | \\ fn getProcAddress(loader: anytype, prefixed_name: [:0]const u8) ?PROC { 717 | \\ const loader_info = @typeInfo(@TypeOf(loader)); 718 | \\ const loader_is_fn = 719 | \\ loader_info == .@"fn" or 720 | \\ loader_info == .pointer and @typeInfo(loader_info.pointer.child) == .@"fn"; 721 | \\ if (loader_is_fn) { 722 | \\ return @as(?PROC, loader(@as([*:0]const u8, prefixed_name))); 723 | \\ } else { 724 | \\ return @as(?PROC, loader.getProcAddress(@as([*:0]const u8, prefixed_name))); 725 | \\ } 726 | \\ } 727 | \\ 728 | ); 729 | if (any_extensions) { 730 | try writer.writeAll( 731 | \\ 732 | \\ fn initExtension(procs: *ProcTable, comptime name: [:0]const u8) bool { 733 | \\ 734 | ); 735 | if (version[0] >= 3) { 736 | // GL 3.0 and GL ES 3.0 both introduced querying extensions by index via 'GetStringi'. 737 | // Starting with GL 3.2, querying extensions via 'GetString' is no longer supported 738 | // under the Core profile. 739 | try writer.writeAll( 740 | \\ var count: c_int = 0; 741 | \\ procs.GetIntegerv(NUM_EXTENSIONS, (&count)[0..1]); 742 | \\ if (count < 0) return false; 743 | \\ var i: c_uint = 0; 744 | \\ while (i < @as(c_uint, @intCast(count))) : (i += 1) { 745 | \\ const prefixed_name = procs.GetStringi(EXTENSIONS, i) orelse return false; 746 | \\ if (std.mem.orderZ(u8, prefixed_name, "GL_" ++ name) == .eq) { 747 | \\ 748 | ); 749 | } else { 750 | try writer.writeAll( 751 | \\ const prefixed_names = procs.GetString(EXTENSIONS) orelse return false; 752 | \\ var it = std.mem.tokenizeScalar(u8, std.mem.span(prefixed_names), ' '); 753 | \\ while (it.next()) |prefixed_name| { 754 | \\ if (std.mem.eql(u8, prefixed_name, "GL_" ++ name)) { 755 | \\ 756 | ); 757 | } 758 | try writer.writeAll( 759 | \\ @field(procs, name) = true; 760 | \\ return true; 761 | \\ } 762 | \\ } 763 | \\ return false; 764 | \\ } 765 | \\ 766 | ); 767 | } 768 | try writer.writeAll( 769 | \\}; 770 | \\ 771 | \\test { 772 | \\ @setEvalBranchQuota(1_000_000); 773 | \\ std.testing.refAllDeclsRecursive(@This()); 774 | \\} 775 | \\ 776 | ); 777 | } 778 | 779 | fn fmtTypeExpr(type_expr: []const registry.Command.Token) std.fmt.Formatter(formatTypeExpr) { 780 | return .{ .data = type_expr }; 781 | } 782 | 783 | fn formatTypeExpr( 784 | type_expr: []const registry.Command.Token, 785 | comptime _: []const u8, 786 | _: std.fmt.FormatOptions, 787 | writer: anytype, 788 | ) !void { 789 | if (type_expr.len == 1 and type_expr[0] == .void) { 790 | return writer.writeAll("void"); 791 | } 792 | for (type_expr, 0..) |token, token_index| switch (token) { 793 | .void => try writer.writeAll("anyopaque"), 794 | .@"*" => { 795 | try writer.writeAll( 796 | if (type_expr[type_expr.len - 1] == .void and for (type_expr[(token_index + 1)..]) |future_token| { 797 | if (future_token == .@"*") break false; 798 | } else true) 799 | "?*" 800 | else 801 | "[*c]", 802 | ); 803 | }, 804 | .@"const" => try writer.writeAll("const "), 805 | .type => |@"type"| try writer.print("{}", .{std.zig.fmtId(@tagName(@"type"))}), 806 | }; 807 | } 808 | 809 | fn getTypeValue(@"type": registry.Type.Name) []const u8 { 810 | return switch (@"type") { 811 | .DEBUGPROC, 812 | .DEBUGPROCARB, 813 | .DEBUGPROCKHR, 814 | => "*const fn (source: @\"enum\", @\"type\": @\"enum\", id: uint, severity: @\"enum\", length: sizei, message: [*:0]const char, userParam: ?*const anyopaque) callconv(APIENTRY) void", 815 | .DEBUGPROCAMD, 816 | => "*const fn (id: uint, category: @\"enum\", severity: @\"enum\", length: sizei, message: [*:0]const char, userParam: ?*anyopaque) callconv(APIENTRY) void", 817 | .VULKANPROCNV, 818 | => "*const fn () callconv(APIENTRY) void", 819 | .bitfield, 820 | .@"enum", 821 | .uint, 822 | => "c_uint", 823 | .boolean, 824 | .char, 825 | .charARB, 826 | .ubyte, 827 | => "u8", 828 | .byte, 829 | => "i8", 830 | .cl_context, 831 | .cl_event, 832 | .eglClientBufferEXT, 833 | .eglImageOES, 834 | .sync, 835 | => "*opaque {}", 836 | .clampd, 837 | .double, 838 | => "f64", 839 | .clampf, 840 | .float, 841 | => "f32", 842 | .clampx, 843 | .fixed, 844 | => "i32", 845 | .half, 846 | .halfARB, 847 | .ushort, 848 | => "u16", 849 | .halfNV, 850 | => "c_ushort", 851 | .handleARB, 852 | => "if (builtin.os.tag.isDarwin()) *allowzero anyopaque else u32", 853 | .int, 854 | .sizei, 855 | => "c_int", 856 | .int64, 857 | .int64EXT, 858 | => "i64", 859 | .intptr, 860 | .intptrARB, 861 | .sizeiptr, 862 | .sizeiptrARB, 863 | => "isize", 864 | .short, 865 | => "i16", 866 | .uint64, 867 | .uint64EXT, 868 | => "u64", 869 | .vdpauSurfaceNV, 870 | => "intptr", 871 | .khrplatform, 872 | .void, 873 | => unreachable, 874 | }; 875 | } 876 | 877 | fn renderParams(writer: anytype, command: ResolvedCommands.Entry, comptime name_only: bool) !void { 878 | for (command.value.params, 0..) |param, param_index| { 879 | if (param_index != 0) try writer.writeAll(", "); 880 | if (paramOverride(command.key, param_index)) |override| { 881 | try writer.print("{}", .{std.zig.fmtId(override.name)}); 882 | if (!name_only) { 883 | try writer.print(": {s}", .{override.type_expr}); 884 | } 885 | } else { 886 | try writer.print("{}", .{std.zig.fmtId(param.name)}); 887 | if (!name_only) { 888 | try writer.print(": {}", .{fmtTypeExpr(param.type_expr)}); 889 | } 890 | } 891 | } 892 | } 893 | 894 | fn paramOverride(command: registry.Command.Name, param_index: usize) ?struct { 895 | name: []const u8, 896 | type_expr: []const u8, 897 | } { 898 | return switch (command) { 899 | .BufferData, 900 | .BufferDataARB, 901 | => switch (param_index) { 902 | 2 => .{ .name = "data", .type_expr = "?*const anyopaque" }, 903 | else => null, 904 | }, 905 | .BufferStorageExternalEXT, 906 | .NamedBufferStorageExternalEXT, 907 | => switch (param_index) { 908 | 3 => .{ .name = "clientBuffer", .type_expr = "eglClientBufferEXT" }, 909 | else => null, 910 | }, 911 | inline .ClearBufferfv, 912 | .ClearBufferiv, 913 | .ClearBufferuiv, 914 | => |tag| switch (param_index) { 915 | 2 => .{ 916 | .name = "values", 917 | .type_expr = "[*]const " ++ switch (tag) { 918 | .ClearBufferfv => "float", 919 | .ClearBufferiv => "int", 920 | .ClearBufferuiv => "uint", 921 | else => comptime unreachable, 922 | }, 923 | }, 924 | else => null, 925 | }, 926 | inline .ClearNamedFramebufferfv, 927 | .ClearNamedFramebufferiv, 928 | .ClearNamedFramebufferuiv, 929 | => |tag| switch (param_index) { 930 | 3 => .{ 931 | .name = "values", 932 | .type_expr = "[*]const " ++ switch (tag) { 933 | .ClearNamedFramebufferfv => "float", 934 | .ClearNamedFramebufferiv => "int", 935 | .ClearNamedFramebufferuiv => "uint", 936 | else => comptime unreachable, 937 | }, 938 | }, 939 | else => null, 940 | }, 941 | .ClientWaitSync, 942 | .ClientWaitSyncAPPLE, 943 | .GetSynciv, 944 | .GetSyncivAPPLE, 945 | .WaitSync, 946 | .WaitSyncAPPLE, 947 | => switch (param_index) { 948 | 0 => .{ .name = "sync_", .type_expr = "sync" }, 949 | else => null, 950 | }, 951 | .CreateSyncFromCLeventARB, 952 | => switch (param_index) { 953 | 0 => .{ .name = "context", .type_expr = "cl_context" }, 954 | 1 => .{ .name = "event", .type_expr = "cl_event" }, 955 | else => null, 956 | }, 957 | inline .DebugMessageCallback, 958 | .DebugMessageCallbackAMD, 959 | .DebugMessageCallbackARB, 960 | .DebugMessageCallbackKHR, 961 | => |tag| switch (param_index) { 962 | 0 => .{ 963 | .name = "callback", 964 | .type_expr = "?" ++ switch (tag) { 965 | .DebugMessageCallbackAMD => "DEBUGPROCAMD", 966 | .DebugMessageCallbackARB => "DEBUGPROCARB", 967 | .DebugMessageCallbackKHR => "DEBUGPROCKHR", 968 | else => "DEBUGPROC", 969 | }, 970 | }, 971 | else => null, 972 | }, 973 | .DeleteBuffers, 974 | .DeleteBuffersARB, 975 | .GenBuffers, 976 | .GenBuffersARB, 977 | => switch (param_index) { 978 | 1 => .{ .name = "buffers", .type_expr = "[*]uint" }, 979 | else => null, 980 | }, 981 | .DeleteFramebuffers, 982 | .DeleteFramebuffersEXT, 983 | .DeleteFramebuffersOES, 984 | .GenFramebuffers, 985 | .GenFramebuffersEXT, 986 | .GenFramebuffersOES, 987 | => switch (param_index) { 988 | 1 => .{ .name = "framebuffers", .type_expr = "[*]uint" }, 989 | else => null, 990 | }, 991 | .DeleteProgramPipelines, 992 | .DeleteProgramPipelinesEXT, 993 | .GenProgramPipelines, 994 | .GenProgramPipelinesEXT, 995 | => switch (param_index) { 996 | 1 => .{ .name = "pipelines", .type_expr = "[*]uint" }, 997 | else => null, 998 | }, 999 | .DeleteProgramsARB, 1000 | .DeleteProgramsNV, 1001 | => switch (param_index) { 1002 | 1 => .{ .name = "programs", .type_expr = "[*]uint" }, 1003 | else => null, 1004 | }, 1005 | .DeleteQueries, 1006 | .DeleteQueriesARB, 1007 | .DeleteQueriesEXT, 1008 | .DeleteTransformFeedbacks, 1009 | .DeleteTransformFeedbacksNV, 1010 | .GenQueries, 1011 | .GenQueriesARB, 1012 | .GenQueriesEXT, 1013 | .GenTransformFeedbacks, 1014 | .GenTransformFeedbacksNV, 1015 | => switch (param_index) { 1016 | 1 => .{ .name = "ids", .type_expr = "[*]uint" }, 1017 | else => null, 1018 | }, 1019 | .DeleteRenderbuffers, 1020 | .DeleteRenderbuffersEXT, 1021 | .DeleteRenderbuffersOES, 1022 | .GenRenderbuffers, 1023 | .GenRenderbuffersEXT, 1024 | .GenRenderbuffersOES, 1025 | => switch (param_index) { 1026 | 1 => .{ .name = "renderbuffers", .type_expr = "[*]uint" }, 1027 | else => null, 1028 | }, 1029 | .DeleteSamplers, 1030 | .GenSamplers, 1031 | => switch (param_index) { 1032 | 1 => .{ .name = "samplers", .type_expr = "[*]uint" }, 1033 | else => null, 1034 | }, 1035 | .DeleteSync, 1036 | .DeleteSyncAPPLE, 1037 | .IsSync, 1038 | .IsSyncAPPLE, 1039 | => switch (param_index) { 1040 | 0 => .{ .name = "sync_", .type_expr = "?sync" }, 1041 | else => null, 1042 | }, 1043 | .DeleteTextures, 1044 | .DeleteTexturesEXT, 1045 | .GenTextures, 1046 | .GenTexturesEXT, 1047 | => switch (param_index) { 1048 | 1 => .{ .name = "textures", .type_expr = "[*]uint" }, 1049 | else => null, 1050 | }, 1051 | .DeleteVertexArrays, 1052 | .DeleteVertexArraysAPPLE, 1053 | .DeleteVertexArraysOES, 1054 | .GenVertexArrays, 1055 | .GenVertexArraysAPPLE, 1056 | .GenVertexArraysOES, 1057 | => switch (param_index) { 1058 | 1 => .{ .name = "arrays", .type_expr = "[*]uint" }, 1059 | else => null, 1060 | }, 1061 | .DrawElements, 1062 | => switch (param_index) { 1063 | 3 => .{ .name = "indices", .type_expr = "usize" }, 1064 | else => null, 1065 | }, 1066 | .EGLImageTargetRenderbufferStorageOES, 1067 | .EGLImageTargetTexStorageEXT, 1068 | .EGLImageTargetTexture2DOES, 1069 | .EGLImageTargetTextureStorageEXT, 1070 | => switch (param_index) { 1071 | 1 => .{ .name = "image", .type_expr = "eglImageOES" }, 1072 | else => null, 1073 | }, 1074 | inline .GetAttribLocation, 1075 | .GetAttribLocationARB, 1076 | .GetUniformLocation, 1077 | .GetUniformLocationARB, 1078 | => |tag| switch (param_index) { 1079 | 1 => .{ 1080 | .name = "name", 1081 | .type_expr = "[*:0]const " ++ switch (tag) { 1082 | .GetAttribLocationARB, .GetUniformLocationARB => "charARB", 1083 | else => "char", 1084 | }, 1085 | }, 1086 | else => null, 1087 | }, 1088 | .GetBooleani_v, 1089 | .GetBooleanIndexedvEXT, 1090 | => switch (param_index) { 1091 | 2 => .{ .name = "data", .type_expr = "[*]boolean" }, 1092 | else => null, 1093 | }, 1094 | .GetBooleanv, 1095 | => switch (param_index) { 1096 | 1 => .{ .name = "data", .type_expr = "[*]boolean" }, 1097 | else => null, 1098 | }, 1099 | .GetDoublei_v, 1100 | .GetDoublei_vEXT, 1101 | .GetDoubleIndexedvEXT, 1102 | => switch (param_index) { 1103 | 2 => .{ 1104 | .name = switch (command) { 1105 | .GetDoublei_vEXT => "params", 1106 | else => "data", 1107 | }, 1108 | .type_expr = "[*]double", 1109 | }, 1110 | else => null, 1111 | }, 1112 | .GetDoublev, 1113 | => switch (param_index) { 1114 | 1 => .{ .name = "data", .type_expr = "[*]double" }, 1115 | else => null, 1116 | }, 1117 | .GetFloati_v, 1118 | .GetFloati_vEXT, 1119 | .GetFloati_vNV, 1120 | .GetFloati_vOES, 1121 | .GetFloatIndexedvEXT, 1122 | => switch (param_index) { 1123 | 2 => .{ 1124 | .name = switch (command) { 1125 | .GetFloati_vEXT => "params", 1126 | else => "data", 1127 | }, 1128 | .type_expr = "[*]float", 1129 | }, 1130 | else => null, 1131 | }, 1132 | .GetFloatv, 1133 | => switch (param_index) { 1134 | 1 => .{ .name = "data", .type_expr = "[*]float" }, 1135 | else => null, 1136 | }, 1137 | .GetInteger64i_v, 1138 | => switch (param_index) { 1139 | 2 => .{ .name = "data", .type_expr = "[*]int64" }, 1140 | else => null, 1141 | }, 1142 | .GetInteger64v, 1143 | .GetInteger64vAPPLE, 1144 | .GetInteger64vEXT, 1145 | => switch (param_index) { 1146 | 1 => .{ 1147 | .name = switch (command) { 1148 | .GetInteger64vAPPLE => "params", 1149 | else => "data", 1150 | }, 1151 | .type_expr = "[*]int64", 1152 | }, 1153 | else => null, 1154 | }, 1155 | .GetIntegeri_v, 1156 | .GetIntegeri_vEXT, 1157 | .GetIntegerIndexedvEXT, 1158 | => switch (param_index) { 1159 | 2 => .{ .name = "data", .type_expr = "[*]int" }, 1160 | else => null, 1161 | }, 1162 | .GetIntegerv, 1163 | => switch (param_index) { 1164 | 1 => .{ .name = "data", .type_expr = "[*]int" }, 1165 | else => null, 1166 | }, 1167 | .GetProgramInfoLog, 1168 | .GetShaderInfoLog, 1169 | => switch (param_index) { 1170 | 2 => .{ .name = "length", .type_expr = "?*sizei" }, 1171 | 3 => .{ .name = "infoLog", .type_expr = "[*]char" }, 1172 | else => null, 1173 | }, 1174 | .GetProgramiv, 1175 | .GetShaderiv, 1176 | => switch (param_index) { 1177 | 2 => .{ .name = "param", .type_expr = "*int" }, 1178 | else => null, 1179 | }, 1180 | .GetShaderPrecisionFormat, 1181 | => switch (param_index) { 1182 | 2 => .{ .name = "range", .type_expr = "*int" }, 1183 | 3 => .{ .name = "precision", .type_expr = "*int" }, 1184 | else => null, 1185 | }, 1186 | inline .GetShaderSource, 1187 | .GetShaderSourceARB, 1188 | => |tag| switch (param_index) { 1189 | 2 => .{ .name = "length", .type_expr = "?*sizei" }, 1190 | 3 => .{ 1191 | .name = "source", 1192 | .type_expr = "[*]" ++ switch (tag) { 1193 | .GetShaderSourceARB => "charARB", 1194 | else => "char", 1195 | }, 1196 | }, 1197 | else => null, 1198 | }, 1199 | .GetVkProcAddrNV, 1200 | => switch (param_index) { 1201 | 0 => .{ .name = "name", .type_expr = "[*:0]const char" }, 1202 | else => null, 1203 | }, 1204 | inline .ShaderSource, 1205 | .ShaderSourceARB, 1206 | => |tag| switch (param_index) { 1207 | 2 => .{ 1208 | .name = "strings", 1209 | .type_expr = "[*]const [*]const " ++ switch (tag) { 1210 | .GetShaderSourceARB => "charARB", 1211 | else => "char", 1212 | }, 1213 | }, 1214 | 3 => .{ .name = "lengths", .type_expr = "?[*]const int" }, 1215 | else => null, 1216 | }, 1217 | .VertexAttribIPointer, 1218 | .VertexAttribIPointerEXT, 1219 | .VertexAttribLPointer, 1220 | .VertexAttribLPointerEXT, 1221 | .VertexAttribPointerNV, 1222 | => switch (param_index) { 1223 | 4 => .{ .name = "pointer", .type_expr = "usize" }, 1224 | else => null, 1225 | }, 1226 | .VertexAttribPointer, 1227 | .VertexAttribPointerARB, 1228 | => switch (param_index) { 1229 | 5 => .{ .name = "pointer", .type_expr = "usize" }, 1230 | else => null, 1231 | }, 1232 | else => null, 1233 | }; 1234 | } 1235 | 1236 | fn renderReturnType(writer: anytype, command: ResolvedCommands.Entry) !void { 1237 | if (returnTypeOverride(command.key)) |override| { 1238 | try writer.writeAll(override.type_expr); 1239 | } else { 1240 | try formatTypeExpr(command.value.return_type_expr, "", .{}, writer); 1241 | } 1242 | } 1243 | 1244 | fn returnTypeOverride(command: registry.Command.Name) ?struct { 1245 | type_expr: []const u8, 1246 | } { 1247 | return switch (command) { 1248 | .CreateSyncFromCLeventARB, 1249 | .FenceSync, 1250 | .FenceSyncAPPLE, 1251 | .ImportSyncEXT, 1252 | => .{ .type_expr = "?sync" }, 1253 | .GetString, 1254 | .GetStringi, 1255 | => .{ .type_expr = "?[*:0]const ubyte" }, 1256 | .GetVkProcAddrNV, 1257 | => .{ .type_expr = "?VULKANPROCNV" }, 1258 | else => null, 1259 | }; 1260 | } 1261 | --------------------------------------------------------------------------------