Serenity Operating System
at master 568 lines 24 kB view raw
1/* 2 * Copyright (c) 2022, Jelle Raaijmakers <jelle@gmta.nl> 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#include <AK/Array.h> 8#include <AK/DeprecatedString.h> 9#include <AK/JsonObject.h> 10#include <AK/NumericLimits.h> 11#include <AK/Optional.h> 12#include <AK/SourceGenerator.h> 13#include <AK/StringBuilder.h> 14#include <AK/StringView.h> 15#include <AK/Vector.h> 16#include <LibCore/ArgsParser.h> 17#include <LibCore/File.h> 18#include <LibMain/Main.h> 19 20struct ArgumentDefinition { 21 Optional<DeprecatedString> name; 22 Optional<DeprecatedString> cpp_type; 23 DeprecatedString expression; 24 Optional<DeprecatedString> cast_to; 25}; 26 27struct FunctionDefinition { 28 DeprecatedString name; 29 DeprecatedString return_type; 30 Vector<ArgumentDefinition> arguments; 31 DeprecatedString implementation; 32 bool unimplemented; 33 DeprecatedString variant_gl_type; 34}; 35 36struct VariantType { 37 DeprecatedString encoded_type; 38 Optional<DeprecatedString> implementation; 39 bool unimplemented; 40}; 41 42struct Variants { 43 Vector<DeprecatedString> api_suffixes { "" }; 44 Vector<u32> argument_counts { NumericLimits<u32>::max() }; 45 Vector<DeprecatedString> argument_defaults { "" }; 46 bool convert_range { false }; 47 Vector<VariantType> types { 48 { 49 .encoded_type = "", 50 .implementation = Optional<DeprecatedString> {}, 51 .unimplemented = false, 52 } 53 }; 54 DeprecatedString pointer_argument { "" }; 55}; 56 57struct EncodedTypeEntry { 58 StringView encoded_type; 59 StringView cpp_type; 60 StringView gl_type; 61}; 62 63// clang-format off 64constexpr static Array<EncodedTypeEntry, 9> type_definitions = { 65 EncodedTypeEntry { "b"sv, "GLbyte"sv, "GL_BYTE"sv }, 66 EncodedTypeEntry { "d"sv, "GLdouble"sv, "GL_DOUBLE"sv }, 67 EncodedTypeEntry { "f"sv, "GLfloat"sv, "GL_FLOAT"sv }, 68 EncodedTypeEntry { "i"sv, "GLint"sv, "GL_INT"sv }, 69 EncodedTypeEntry { "s"sv, "GLshort"sv, "GL_SHORT"sv }, 70 EncodedTypeEntry { "ub"sv, "GLubyte"sv, "GL_UNSIGNED_BYTE"sv }, 71 EncodedTypeEntry { "ui"sv, "GLuint"sv, "GL_UNSIGNED_INT"sv }, 72 EncodedTypeEntry { "us"sv, "GLushort"sv, "GL_UNSIGNED_SHORT"sv }, 73 EncodedTypeEntry { "x"sv, "GLfixed"sv, "GL_INT"sv }, 74}; 75// clang-format on 76 77struct EncodedType { 78 EncodedTypeEntry type_entry; 79 DeprecatedString cpp_type; 80 DeprecatedString function_name_suffix; 81 bool is_pointer; 82 bool is_const_pointer; 83}; 84 85Vector<DeprecatedString> get_name_list(Optional<JsonValue const&> name_definition) 86{ 87 if (!name_definition.has_value() || name_definition->is_null()) 88 return {}; 89 90 Vector<DeprecatedString, 1> names; 91 if (name_definition->is_string()) { 92 names.append(name_definition->as_string()); 93 } else if (name_definition->is_array()) { 94 name_definition->as_array().for_each([&names](auto& value) { 95 VERIFY(value.is_string()); 96 names.append(value.as_string()); 97 }); 98 } else { 99 VERIFY_NOT_REACHED(); 100 } 101 return names; 102} 103 104Optional<EncodedType> get_encoded_type(DeprecatedString encoded_type) 105{ 106 bool is_const_pointer = !encoded_type.ends_with('!'); 107 if (!is_const_pointer) 108 encoded_type = encoded_type.substring_view(0, encoded_type.length() - 1); 109 DeprecatedString function_name_suffix = encoded_type; 110 111 bool is_pointer = encoded_type.ends_with('v'); 112 if (is_pointer) 113 encoded_type = encoded_type.substring_view(0, encoded_type.length() - 1); 114 115 VERIFY(is_const_pointer || is_pointer); 116 117 Optional<EncodedTypeEntry> type_definition; 118 for (size_t i = 0; i < type_definitions.size(); ++i) { 119 if (type_definitions[i].encoded_type == encoded_type) { 120 type_definition = type_definitions[i]; 121 break; 122 } 123 } 124 125 if (!type_definition.has_value()) 126 return {}; 127 128 return EncodedType { 129 .type_entry = type_definition.value(), 130 .cpp_type = DeprecatedString::formatted( 131 "{}{}{}", 132 type_definition->cpp_type, 133 is_pointer && is_const_pointer ? " const" : "", 134 is_pointer ? "*" : ""), 135 .function_name_suffix = function_name_suffix, 136 .is_pointer = is_pointer, 137 .is_const_pointer = is_const_pointer, 138 }; 139} 140 141DeprecatedString wrap_expression_in_range_conversion(DeprecatedString source_type, DeprecatedString target_type, DeprecatedString expression) 142{ 143 VERIFY(target_type == "GLfloat" || target_type == "GLdouble"); 144 145 // No range conversion required 146 if (source_type == target_type || source_type == "GLdouble") 147 return expression; 148 149 if (source_type == "GLbyte") 150 return DeprecatedString::formatted("({} + 128.) / 127.5 - 1.", expression); 151 else if (source_type == "GLfloat") 152 return DeprecatedString::formatted("static_cast<GLdouble>({})", expression); 153 else if (source_type == "GLint") 154 return DeprecatedString::formatted("({} + 2147483648.) / 2147483647.5 - 1.", expression); 155 else if (source_type == "GLshort") 156 return DeprecatedString::formatted("({} + 32768.) / 32767.5 - 1.", expression); 157 else if (source_type == "GLubyte") 158 return DeprecatedString::formatted("{} / 255.", expression); 159 else if (source_type == "GLuint") 160 return DeprecatedString::formatted("{} / 4294967296.", expression); 161 else if (source_type == "GLushort") 162 return DeprecatedString::formatted("{} / 65536.", expression); 163 VERIFY_NOT_REACHED(); 164} 165 166Variants read_variants_settings(JsonObject const& variants_obj) 167{ 168 Variants variants; 169 170 if (variants_obj.has_array("argument_counts"sv)) { 171 variants.argument_counts.clear_with_capacity(); 172 variants_obj.get_array("argument_counts"sv)->for_each([&](auto const& argument_count_value) { 173 variants.argument_counts.append(argument_count_value.to_u32()); 174 }); 175 } 176 if (variants_obj.has_array("argument_defaults"sv)) { 177 variants.argument_defaults.clear_with_capacity(); 178 variants_obj.get_array("argument_defaults"sv)->for_each([&](auto const& argument_default_value) { 179 variants.argument_defaults.append(argument_default_value.as_string()); 180 }); 181 } 182 if (variants_obj.has_bool("convert_range"sv)) { 183 variants.convert_range = variants_obj.get_bool("convert_range"sv).value(); 184 } 185 if (variants_obj.has_array("api_suffixes"sv)) { 186 variants.api_suffixes.clear_with_capacity(); 187 variants_obj.get_array("api_suffixes"sv)->for_each([&](auto const& suffix_value) { 188 variants.api_suffixes.append(suffix_value.as_string()); 189 }); 190 } 191 if (variants_obj.has_string("pointer_argument"sv)) { 192 variants.pointer_argument = variants_obj.get_deprecated_string("pointer_argument"sv).value(); 193 } 194 if (variants_obj.has_object("types"sv)) { 195 variants.types.clear_with_capacity(); 196 variants_obj.get_object("types"sv)->for_each_member([&](auto const& key, auto const& type_value) { 197 auto const& type = type_value.as_object(); 198 variants.types.append(VariantType { 199 .encoded_type = key, 200 .implementation = type.get_deprecated_string("implementation"sv), 201 .unimplemented = type.get_bool("unimplemented"sv).value_or(false), 202 }); 203 }); 204 } 205 206 return variants; 207} 208 209Vector<ArgumentDefinition> copy_arguments_for_variant(Vector<ArgumentDefinition> arguments, Variants variants, 210 u32 argument_count, EncodedType encoded_type) 211{ 212 Vector<ArgumentDefinition> variant_arguments = arguments; 213 auto base_cpp_type = encoded_type.type_entry.cpp_type; 214 215 size_t variadic_index = 0; 216 for (size_t i = 0; i < variant_arguments.size(); ++i) { 217 // Skip arguments with a fixed type 218 if (variant_arguments[i].cpp_type.has_value()) 219 continue; 220 221 variant_arguments[i].cpp_type = encoded_type.cpp_type; 222 auto cast_to = variant_arguments[i].cast_to; 223 224 // Pointer argument 225 if (encoded_type.is_pointer) { 226 variant_arguments[i].name = (variadic_index == 0) ? variants.pointer_argument : Optional<DeprecatedString> {}; 227 228 if (variadic_index >= argument_count) { 229 // If this variable argument is past the argument count, fall back to the defaults 230 variant_arguments[i].expression = variants.argument_defaults[variadic_index]; 231 variant_arguments[i].cast_to = Optional<DeprecatedString> {}; 232 233 } else if (argument_count == 1 && variants.argument_counts.size() == 1) { 234 // Otherwise, if the pointer is the only variadic argument, pass it through unchanged 235 variant_arguments[i].cast_to = Optional<DeprecatedString> {}; 236 237 } else { 238 // Otherwise, index into the pointer argument 239 auto indexed_expression = DeprecatedString::formatted("{}[{}]", variants.pointer_argument, variadic_index); 240 if (variants.convert_range && cast_to.has_value()) 241 indexed_expression = wrap_expression_in_range_conversion(base_cpp_type, cast_to.value(), indexed_expression); 242 variant_arguments[i].expression = indexed_expression; 243 } 244 245 } else { 246 // Regular argument 247 if (variadic_index >= argument_count) { 248 // If the variable argument is past the argument count, fall back to the defaults 249 variant_arguments[i].name = Optional<DeprecatedString> {}; 250 variant_arguments[i].expression = variants.argument_defaults[variadic_index]; 251 variant_arguments[i].cast_to = Optional<DeprecatedString> {}; 252 253 } else if (variants.convert_range && cast_to.has_value()) { 254 // Otherwise, if we need to convert the input values, wrap the expression in a range conversion 255 variant_arguments[i].expression = wrap_expression_in_range_conversion( 256 base_cpp_type, 257 cast_to.value(), 258 variant_arguments[i].expression); 259 } 260 } 261 262 // Determine if we can skip casting to the target type 263 if (cast_to == base_cpp_type || (variants.convert_range && cast_to == "GLdouble")) 264 variant_arguments[i].cast_to = Optional<DeprecatedString> {}; 265 266 variadic_index++; 267 } 268 269 return variant_arguments; 270} 271 272Vector<FunctionDefinition> create_function_definitions(DeprecatedString function_name, JsonObject const& function_definition) 273{ 274 // A single function definition can expand to multiple generated functions by way of: 275 // - differing API suffices (ARB, EXT, etc.); 276 // - differing argument counts; 277 // - differing argument types. 278 // These can all be combined. 279 280 // Parse base argument definitions first; these may later be modified by variants 281 Vector<ArgumentDefinition> argument_definitions; 282 JsonArray const& arguments = function_definition.get_array("arguments"sv).value_or(JsonArray {}); 283 arguments.for_each([&argument_definitions](auto const& argument_value) { 284 VERIFY(argument_value.is_object()); 285 auto const& argument = argument_value.as_object(); 286 287 auto type = argument.get_deprecated_string("type"sv); 288 auto argument_names = get_name_list(argument.get("name"sv)); 289 auto expression = argument.get_deprecated_string("expression"sv).value_or("@argument_name@"); 290 auto cast_to = argument.get_deprecated_string("cast_to"sv); 291 292 // Add an empty dummy name when all we have is an expression 293 if (argument_names.is_empty() && !expression.is_empty()) 294 argument_names.append(""); 295 296 for (auto const& argument_name : argument_names) { 297 argument_definitions.append({ .name = argument_name.is_empty() ? Optional<DeprecatedString> {} : argument_name, 298 .cpp_type = type, 299 .expression = expression, 300 .cast_to = cast_to }); 301 } 302 }); 303 304 // Create functions for each name and/or variant 305 Vector<FunctionDefinition> functions; 306 307 auto return_type = function_definition.get_deprecated_string("return_type"sv).value_or("void"); 308 auto function_implementation = function_definition.get_deprecated_string("implementation"sv).value_or(function_name.to_snakecase()); 309 auto function_unimplemented = function_definition.get_bool("unimplemented"sv).value_or(false); 310 311 if (!function_definition.has("variants"sv)) { 312 functions.append({ 313 .name = function_name, 314 .return_type = return_type, 315 .arguments = argument_definitions, 316 .implementation = function_implementation, 317 .unimplemented = function_unimplemented, 318 .variant_gl_type = "", 319 }); 320 return functions; 321 } 322 323 // Read variants settings for this function 324 auto variants_obj = function_definition.get_object("variants"sv).value(); 325 auto variants = read_variants_settings(variants_obj); 326 327 for (auto argument_count : variants.argument_counts) { 328 for (auto const& variant_type : variants.types) { 329 auto encoded_type = get_encoded_type(variant_type.encoded_type); 330 auto variant_arguments = encoded_type.has_value() 331 ? copy_arguments_for_variant(argument_definitions, variants, argument_count, encoded_type.value()) 332 : argument_definitions; 333 auto variant_type_implementation = variant_type.implementation.has_value() 334 ? variant_type.implementation.value() 335 : function_implementation; 336 337 for (auto const& api_suffix : variants.api_suffixes) { 338 functions.append({ 339 .name = DeprecatedString::formatted( 340 "{}{}{}{}", 341 function_name, 342 variants.argument_counts.size() > 1 ? DeprecatedString::formatted("{}", argument_count) : "", 343 encoded_type.has_value() && variants.types.size() > 1 ? encoded_type->function_name_suffix : "", 344 api_suffix), 345 .return_type = return_type, 346 .arguments = variant_arguments, 347 .implementation = variant_type_implementation, 348 .unimplemented = variant_type.unimplemented || function_unimplemented, 349 .variant_gl_type = encoded_type.has_value() ? encoded_type->type_entry.gl_type : ""sv, 350 }); 351 } 352 } 353 } 354 355 return functions; 356} 357 358ErrorOr<void> generate_header_file(JsonObject& api_data, Core::File& file) 359{ 360 StringBuilder builder; 361 SourceGenerator generator { builder }; 362 363 generator.appendln("#pragma once"); 364 generator.append("\n"); 365 generator.appendln("#include <LibGL/GL/glplatform.h>"); 366 generator.append("\n"); 367 generator.appendln("#ifdef __cplusplus"); 368 generator.appendln("extern \"C\" {"); 369 generator.appendln("#endif"); 370 generator.append("\n"); 371 372 api_data.for_each_member([&](auto& function_name, auto& value) { 373 VERIFY(value.is_object()); 374 auto const& function = value.as_object(); 375 auto function_definitions = create_function_definitions(function_name, function); 376 377 for (auto const& function_definition : function_definitions) { 378 auto function_generator = generator.fork(); 379 380 function_generator.set("name", function_definition.name); 381 function_generator.set("return_type", function_definition.return_type); 382 383 function_generator.append("GLAPI @return_type@ gl@name@("); 384 385 bool first = true; 386 for (auto const& argument_definition : function_definition.arguments) { 387 if (!argument_definition.name.has_value() || !argument_definition.cpp_type.has_value()) 388 continue; 389 390 auto argument_generator = function_generator.fork(); 391 argument_generator.set("argument_type", argument_definition.cpp_type.value()); 392 argument_generator.set("argument_name", argument_definition.name.value()); 393 394 if (!first) 395 argument_generator.append(", "); 396 first = false; 397 argument_generator.append("@argument_type@ @argument_name@"); 398 } 399 400 function_generator.appendln(");"); 401 } 402 }); 403 404 generator.appendln("#ifdef __cplusplus"); 405 generator.appendln("}"); 406 generator.appendln("#endif"); 407 408 TRY(file.write_until_depleted(generator.as_string_view().bytes())); 409 return {}; 410} 411 412ErrorOr<void> generate_implementation_file(JsonObject& api_data, Core::File& file) 413{ 414 StringBuilder builder; 415 SourceGenerator generator { builder }; 416 417 generator.appendln("#include <LibGL/GL/glapi.h>"); 418 generator.appendln("#include <LibGL/GLContext.h>"); 419 generator.append("\n"); 420 generator.appendln("extern GL::GLContext* g_gl_context;"); 421 generator.append("\n"); 422 423 api_data.for_each_member([&](auto& function_name, auto& value) { 424 VERIFY(value.is_object()); 425 JsonObject const& function = value.as_object(); 426 auto function_definitions = create_function_definitions(function_name, function); 427 428 for (auto const& function_definition : function_definitions) { 429 auto function_generator = generator.fork(); 430 auto return_type = function_definition.return_type; 431 432 function_generator.set("name"sv, function_definition.name); 433 function_generator.set("return_type"sv, return_type); 434 function_generator.set("implementation"sv, function_definition.implementation); 435 function_generator.set("variant_gl_type"sv, function_definition.variant_gl_type); 436 437 function_generator.append("@return_type@ gl@name@("); 438 439 bool first = true; 440 for (auto const& argument_definition : function_definition.arguments) { 441 if (!argument_definition.name.has_value() || !argument_definition.cpp_type.has_value()) 442 continue; 443 444 auto argument_generator = function_generator.fork(); 445 argument_generator.set("argument_type", argument_definition.cpp_type.value()); 446 argument_generator.set("argument_name", argument_definition.name.value()); 447 448 if (!first) 449 argument_generator.append(", "); 450 first = false; 451 argument_generator.append("@argument_type@ @argument_name@"); 452 } 453 function_generator.appendln(")"); 454 function_generator.appendln("{"); 455 456 if (function_definition.unimplemented) { 457 function_generator.append(" dbgln(\"gl@name@("); 458 459 first = true; 460 for (auto const& argument_definition : function_definition.arguments) { 461 if (!argument_definition.name.has_value()) 462 continue; 463 if (!first) 464 function_generator.append(", "); 465 first = false; 466 if (argument_definition.cpp_type.value().ends_with('*')) 467 function_generator.append("{:p}"); 468 else if (argument_definition.cpp_type.value() == "GLenum") 469 function_generator.append("{:#x}"); 470 else 471 function_generator.append("{}"); 472 } 473 474 function_generator.append("): unimplemented\""); 475 476 for (auto const& argument_definition : function_definition.arguments) { 477 if (!argument_definition.name.has_value()) 478 continue; 479 480 function_generator.append(", "); 481 function_generator.append(argument_definition.name.value()); 482 } 483 484 function_generator.appendln(");"); 485 function_generator.appendln(" TODO();"); 486 } else { 487 function_generator.appendln(" if (!g_gl_context)"); 488 if (return_type.ends_with('*')) 489 function_generator.appendln(" return nullptr;"); 490 else if (return_type == "GLboolean"sv) 491 function_generator.appendln(" return GL_FALSE;"); 492 else if (return_type == "GLenum"sv) 493 function_generator.appendln(" return GL_INVALID_OPERATION;"); 494 else if (return_type == "GLuint"sv) 495 function_generator.appendln(" return 0;"); 496 else if (return_type == "void"sv) 497 function_generator.appendln(" return;"); 498 else 499 VERIFY_NOT_REACHED(); 500 function_generator.append(" "); 501 if (return_type != "void"sv) 502 function_generator.append("return "); 503 function_generator.append("g_gl_context->gl_@implementation@("); 504 505 first = true; 506 for (auto const& argument_definition : function_definition.arguments) { 507 auto argument_generator = function_generator.fork(); 508 509 auto cast_to = argument_definition.cast_to; 510 argument_generator.set("argument_name", argument_definition.name.value_or("")); 511 argument_generator.set("cast_to", cast_to.value_or("")); 512 513 if (!first) 514 argument_generator.append(", "); 515 first = false; 516 517 if (cast_to.has_value()) 518 argument_generator.append("static_cast<@cast_to@>("); 519 argument_generator.append(argument_definition.expression); 520 if (cast_to.has_value()) 521 argument_generator.append(")"); 522 } 523 524 function_generator.appendln(");"); 525 } 526 527 function_generator.appendln("}"); 528 function_generator.append("\n"); 529 } 530 }); 531 532 TRY(file.write_until_depleted(generator.as_string_view().bytes())); 533 return {}; 534} 535 536ErrorOr<JsonValue> read_entire_file_as_json(StringView filename) 537{ 538 auto file = TRY(Core::File::open(filename, Core::File::OpenMode::Read)); 539 auto json_size = TRY(file->size()); 540 auto json_data = TRY(ByteBuffer::create_uninitialized(json_size)); 541 TRY(file->read_until_filled(json_data.bytes())); 542 return JsonValue::from_string(json_data); 543} 544 545ErrorOr<int> serenity_main(Main::Arguments arguments) 546{ 547 StringView generated_header_path; 548 StringView generated_implementation_path; 549 StringView api_json_path; 550 551 Core::ArgsParser args_parser; 552 args_parser.add_option(generated_header_path, "Path to the OpenGL API header file to generate", "generated-header-path", 'h', "generated-header-path"); 553 args_parser.add_option(generated_implementation_path, "Path to the OpenGL API implementation file to generate", "generated-implementation-path", 'c', "generated-implementation-path"); 554 args_parser.add_option(api_json_path, "Path to the JSON file to read from", "json-path", 'j', "json-path"); 555 args_parser.parse(arguments); 556 557 auto json = TRY(read_entire_file_as_json(api_json_path)); 558 VERIFY(json.is_object()); 559 auto api_data = json.as_object(); 560 561 auto generated_header_file = TRY(Core::File::open(generated_header_path, Core::File::OpenMode::Write)); 562 auto generated_implementation_file = TRY(Core::File::open(generated_implementation_path, Core::File::OpenMode::Write)); 563 564 TRY(generate_header_file(api_data, *generated_header_file)); 565 TRY(generate_implementation_file(api_data, *generated_implementation_file)); 566 567 return 0; 568}