glbindify.cpp 33 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100
  1. #include <stdint.h>
  2. #include <iostream>
  3. #include <vector>
  4. #include <string>
  5. #include <map>
  6. #include <set>
  7. #include <fstream>
  8. #include <stdio.h>
  9. #include <math.h>
  10. #include <errno.h>
  11. #include <stdio.h>
  12. #include <errno.h>
  13. #if defined(_WIN32)
  14. #define strdup _strdup
  15. #include "getopt.h"
  16. #else
  17. #include <getopt.h>
  18. #endif
  19. #include "tinyxml2.h"
  20. #ifdef HAVE_CONFIG_H
  21. #include "config.h"
  22. #else
  23. #define PACKAGE_VERSION "<unknown>"
  24. #define PACKAGE_STRING "<unknown>"
  25. #endif
  26. #define USE_GPERF HAVE_GPERF && !defined(_WIN32)
  27. #if USE_GPERF
  28. #include <unistd.h>
  29. #include <sys/wait.h>
  30. #include <sys/types.h>
  31. #endif
  32. enum API {
  33. API_GL,
  34. API_GLES2,
  35. API_EGL,
  36. API_GLX,
  37. API_WGL
  38. };
  39. enum API g_api;
  40. using namespace tinyxml2;
  41. std::string g_indent_string;
  42. const char *g_prefix;
  43. const char *g_macro_prefix;
  44. #define FOREACH(var, cont, type) \
  45. for (type::iterator var = cont.begin(); var != cont.end(); var++)
  46. #define FOREACH_CONST(var, cont, type) \
  47. for (type::const_ ## iterator var = cont.begin(); var != cont.end(); var++)
  48. void increase_indent()
  49. {
  50. g_indent_string.push_back('\t');
  51. }
  52. void decrease_indent()
  53. {
  54. if (g_indent_string.size() > 0)
  55. g_indent_string.resize(g_indent_string.size() -1);
  56. }
  57. void reset_indent()
  58. {
  59. g_indent_string.clear();
  60. }
  61. int indent_fprintf(FILE *file, const char *format, ...)
  62. {
  63. va_list args;
  64. va_start(args, format);
  65. fputs(g_indent_string.c_str(), file);
  66. return vfprintf(file, format, args);
  67. }
  68. static inline bool tag_test(const XMLNode &elem, const char *value)
  69. {
  70. return !strcmp(elem.Value(), value);
  71. }
  72. static inline bool parent_tag_test(const XMLNode &elem, const char *value)
  73. {
  74. return elem.Parent() && tag_test(*elem.Parent(), value);
  75. }
  76. static inline bool tag_stack_test(const XMLNode &elem, const char *value, const char *parent_value)
  77. {
  78. return tag_test(elem, value) && elem.Parent() && tag_test(*elem.Parent(), parent_value);
  79. }
  80. static inline bool parent_tag_stack_test(const XMLNode &elem, const char *value, const char *parent_value)
  81. {
  82. return elem.Parent() && tag_stack_test(*elem.Parent(), value, parent_value);
  83. }
  84. struct cstring_compare {
  85. bool operator()(const char *a, const char *b) const {
  86. return strcmp(a, b) < 0;
  87. }
  88. };
  89. struct enumeration {
  90. const char *name;
  91. std::map<const char *, unsigned int, cstring_compare> enum_map;
  92. };
  93. std::set<const char *, cstring_compare> g_common_gl_typedefs;
  94. struct command {
  95. const char *name;
  96. const char *type;
  97. std::string type_decl;
  98. struct param {
  99. const char *type;
  100. const char *name;
  101. std::string decl;
  102. };
  103. std::vector<param> params;
  104. void print_declare(FILE *out, const char *command_prefix) {
  105. indent_fprintf(out, "extern %s (*%s%s)(", type_decl.c_str(), command_prefix, name);
  106. if (params.size()) {
  107. fprintf(out, "%s", params[0].decl.c_str());
  108. for(unsigned int i = 1; i < params.size(); i++) {
  109. fprintf(out, ", %s", params[i].decl.c_str());
  110. }
  111. }
  112. fprintf(out, ");\n");
  113. }
  114. void print_initialize(FILE *out, const char *command_prefix) {
  115. indent_fprintf(out, "%s (*%s%s)(", type_decl.c_str(), command_prefix, name);
  116. if (params.size()) {
  117. fprintf(out, "%s", params[0].decl.c_str());
  118. for(unsigned int i = 1; i < params.size(); i++) {
  119. fprintf(out, ", %s", params[i].decl.c_str());
  120. }
  121. }
  122. fprintf(out, ") = NULL;\n");
  123. }
  124. void print_load(FILE *out, const char *command_prefix) {
  125. indent_fprintf(out, "%s%s = (%s (*)(", command_prefix, name, type_decl.c_str());
  126. if (params.size()) {
  127. fprintf(out, "%s", params[0].decl.c_str());
  128. for(unsigned int i = 1; i < params.size(); i++) {
  129. fprintf(out, ", %s", params[i].decl.c_str());
  130. }
  131. }
  132. fprintf(out, ") ) LoadProcAddress(\"%s%s\");\n", command_prefix, name);
  133. }
  134. command() : name(NULL), type(NULL) {}
  135. };
  136. typedef std::map<const char *, command *, cstring_compare> commands_type;
  137. typedef std::set<const char *, cstring_compare> enums_type;
  138. struct interface {
  139. enums_type enums;
  140. commands_type commands;
  141. enums_type removed_enums;
  142. commands_type removed_commands;
  143. };
  144. //Api description
  145. const char *g_api_name;
  146. const char *g_variant_name;
  147. const char *g_command_prefix;
  148. const char *g_enumeration_prefix;
  149. const char *g_api_print_name;;
  150. //List of all enums and commands
  151. typedef std::map<const char *, unsigned int, cstring_compare> enum_map_type;
  152. typedef std::map<const char *, const char *, cstring_compare> enum_str_map_type;
  153. enum_map_type g_enum_map;
  154. enum_str_map_type g_enum_str_map;
  155. std::vector<enumeration *> g_enumerations;
  156. typedef std::map<const char *, command *, cstring_compare> commands_type;
  157. commands_type g_commands;
  158. typedef std::vector<std::string> types_type;
  159. types_type g_types;
  160. typedef std::map<int, interface *> feature_interfaces_type;
  161. feature_interfaces_type g_feature_interfaces;
  162. typedef std::map<const char *, interface *, cstring_compare> extension_interfaces_type;
  163. extension_interfaces_type g_extension_interfaces;
  164. bool is_command_in_namespace(const char **name)
  165. {
  166. if (strstr(*name, g_command_prefix)) {
  167. *name = *name + strlen(g_command_prefix);
  168. return true;
  169. } else {
  170. return false;
  171. }
  172. }
  173. bool is_enum_in_namespace(const char **name)
  174. {
  175. if (strstr(*name, g_enumeration_prefix) == *name) {
  176. *name = *name + strlen(g_enumeration_prefix);
  177. return true;
  178. } else {
  179. return false;
  180. }
  181. }
  182. void bindify(const char *header_name, int min_version, FILE *header_file, FILE *source_file);
  183. template <class T>
  184. class data_builder_visitor : public XMLVisitor
  185. {
  186. protected:
  187. T *m_data;
  188. private:
  189. const XMLElement &m_root;
  190. virtual bool visit(const XMLText &text) { return true; }
  191. bool Visit(const XMLText &text) { return visit(text); }
  192. virtual bool visit_begin(const XMLElement &elem, const XMLAttribute *attrib) { return true; }
  193. virtual bool visit_enter(const XMLElement &elem, const XMLAttribute *attrib) { return true; }
  194. bool VisitEnter(const XMLElement &elem, const XMLAttribute *attrib)
  195. {
  196. if (&elem == &m_root) {
  197. return visit_begin(elem, attrib);
  198. } else {
  199. return visit_enter(elem, attrib);
  200. }
  201. }
  202. virtual bool visit_end(const XMLElement &elem, const XMLAttribute *attrib) { return true; }
  203. virtual bool visit_exit(const XMLElement &elem, const XMLAttribute *attrib) { return true; }
  204. bool VisitExit(const XMLElement &elem, const XMLAttribute *attrib)
  205. {
  206. if (&elem == &m_root) {
  207. return visit_end(elem, attrib);
  208. } else {
  209. return visit_exit(elem, attrib);
  210. }
  211. }
  212. public:
  213. data_builder_visitor(const XMLElement &root) :
  214. m_data(new T()),
  215. m_root(root)
  216. {
  217. }
  218. T *build()
  219. {
  220. m_root.Accept(this);
  221. return m_data;
  222. }
  223. };
  224. class command_visitor : public data_builder_visitor<command>
  225. {
  226. virtual bool visit(const XMLText &text)
  227. {
  228. if (!m_data)
  229. return false;
  230. if (parent_tag_test(text, "param")) {
  231. m_data->params.back().decl += text.Value();
  232. } else if (parent_tag_stack_test(text, "name", "param")) {
  233. m_data->params.back().name = text.Value();
  234. } else if (parent_tag_stack_test(text, "ptype", "param")) {
  235. m_data->params.back().type = text.Value();
  236. m_data->params.back().decl += text.Value();
  237. } else if (parent_tag_test(text, "proto")) {
  238. m_data->type_decl += text.Value();
  239. } else if (parent_tag_stack_test(text, "name", "proto")) {
  240. const char *command_name = text.Value();
  241. if (is_command_in_namespace(&command_name)) {
  242. m_data->name = command_name;
  243. return true;
  244. } else {
  245. delete m_data;
  246. m_data = NULL;
  247. return false;
  248. }
  249. } else if (parent_tag_stack_test(text, "ptype", "proto")) {
  250. m_data->type = text.Value();
  251. m_data->type_decl += text.Value();
  252. }
  253. return true;
  254. }
  255. virtual bool visit_enter(const XMLElement &elem, const XMLAttribute *attrib)
  256. {
  257. if (!m_data)
  258. return false;
  259. if (tag_test(elem, "proto")) {
  260. return true;
  261. } else if (tag_stack_test(elem, "ptype", "proto")) {
  262. return true;
  263. } else if (tag_stack_test(elem, "name", "proto")) {
  264. return true;
  265. } else if (tag_test(elem, "param")) {
  266. m_data->params.push_back(command::param());
  267. return true;
  268. } else if (tag_stack_test(elem, "name", "param")) {
  269. return true;
  270. } else if (tag_stack_test(elem, "ptype", "param")) {
  271. return true;
  272. } else {
  273. return false;
  274. }
  275. }
  276. public:
  277. command_visitor(const XMLElement &tag) :
  278. data_builder_visitor<command>(tag)
  279. {
  280. }
  281. };
  282. class enumeration_visitor : public data_builder_visitor<enumeration>
  283. {
  284. virtual bool visit_begin(const XMLElement &elem, const XMLAttribute *attrib)
  285. {
  286. const char *group_c = elem.Attribute("group");
  287. if (group_c)
  288. m_data->name = group_c;
  289. return true;
  290. }
  291. virtual bool visit_enter(const XMLElement &elem, const XMLAttribute *attrib)
  292. {
  293. if (tag_test(elem, "enum")) {
  294. if (elem.Attribute("api") && strcmp(elem.Attribute("api"), g_api_name))
  295. return false;
  296. unsigned int val = 0xffffffff;
  297. const char *enumeration_name = elem.Attribute("name");
  298. if (is_enum_in_namespace(&enumeration_name)) {
  299. int ret = sscanf(elem.Attribute("value"), "0x%x", &val);
  300. if (ret != 1)
  301. ret = sscanf(elem.Attribute("value"), "%d", &val);
  302. if (ret == 1) {
  303. m_data->enum_map[enumeration_name] = val;
  304. g_enum_map[enumeration_name] = val;
  305. } else {
  306. g_enum_str_map[enumeration_name] = strdup(elem.Attribute("value"));
  307. }
  308. }
  309. }
  310. return false;
  311. }
  312. public:
  313. enumeration_visitor(const XMLElement &tag) :
  314. data_builder_visitor<enumeration>(tag)
  315. {
  316. }
  317. };
  318. class interface_visitor : public XMLVisitor
  319. {
  320. const XMLElement &m_root;
  321. interface *m_interface;
  322. bool VisitEnter(const XMLElement &elem, const XMLAttribute *attrib)
  323. {
  324. if (&elem == &m_root) {
  325. return true;
  326. } else if (tag_test(elem, "require") && elem.Parent() == &m_root) {
  327. return g_api != API_GL || !elem.Attribute("profile") || !strcmp(elem.Attribute("profile"), "core");
  328. } else if (tag_test(elem, "remove") && elem.Parent() == &m_root) {
  329. return g_api != API_GL || !elem.Attribute("profile") || !strcmp(elem.Attribute("profile"), "core");
  330. } else if (tag_stack_test(elem, "enum", "require")) {
  331. const char *enumeration_name = elem.Attribute("name");
  332. if (is_enum_in_namespace(&enumeration_name)) {
  333. m_interface->enums.insert(enumeration_name);
  334. return true;
  335. } else {
  336. return false;
  337. }
  338. } else if (tag_stack_test(elem, "enum", "remove")) {
  339. const char *enumeration_name = elem.Attribute("name");
  340. if (is_enum_in_namespace(&enumeration_name)) {
  341. m_interface->removed_enums.insert(enumeration_name);
  342. return true;
  343. } else {
  344. return false;
  345. }
  346. } else if (tag_stack_test(elem, "command", "require")) {
  347. const char *command_name = elem.Attribute("name");
  348. if (is_command_in_namespace(&command_name)) {
  349. m_interface->commands[command_name] = g_commands[command_name];
  350. return true;
  351. } else {
  352. return false;
  353. }
  354. } else if (tag_stack_test(elem, "command", "remove")) {
  355. const char *command_name = elem.Attribute("name");
  356. if (is_command_in_namespace(&command_name)) {
  357. m_interface->removed_commands[command_name] = g_commands[command_name];
  358. return true;
  359. } else {
  360. return false;
  361. }
  362. }
  363. return false;
  364. }
  365. public:
  366. interface_visitor(const XMLElement &root, interface *interface) :
  367. m_root(root), m_interface(interface) {}
  368. };
  369. class type_visitor : public XMLVisitor
  370. {
  371. std::string m_type_decl;
  372. const char *m_type_name;
  373. bool Visit(const XMLText &text)
  374. {
  375. if (parent_tag_test(text, "type")) {
  376. m_type_decl += text.Value();
  377. } else if (parent_tag_stack_test(text, "name", "type")) {
  378. m_type_decl += text.Value();
  379. m_type_name = text.Value();
  380. }
  381. return true;
  382. }
  383. bool VisitEnter(const XMLElement &elem, const XMLAttribute *attrib)
  384. {
  385. if (tag_stack_test(elem, "type", "types")) {
  386. return !elem.Attribute("api") || (elem.Attribute("api") == g_api_name);
  387. } else if (tag_stack_test(elem, "name", "type")) {
  388. return true;
  389. } else {
  390. return false;
  391. }
  392. }
  393. bool VisitExit(const XMLElement &elem)
  394. {
  395. if (m_type_name != NULL) {
  396. if (tag_test(elem, "type")) {
  397. if (!g_common_gl_typedefs.count(m_type_name)) {
  398. g_common_gl_typedefs.insert(m_type_name);
  399. g_types.push_back(m_type_decl);
  400. }
  401. }
  402. }
  403. return true;
  404. }
  405. public:
  406. type_visitor() : m_type_name(NULL) {}
  407. };
  408. class khronos_registry_visitor : public XMLVisitor
  409. {
  410. XMLDocument &m_doc;
  411. bool VisitEnter(const XMLElement &elem, const XMLAttribute *attrib)
  412. {
  413. if (tag_test(elem, "registry") && elem.Parent() == &m_doc) {
  414. return true;
  415. } else if (tag_stack_test(elem, "commands", "registry")) {
  416. return true;
  417. } else if (tag_stack_test(elem, "extensions", "registry")) {
  418. return true;
  419. } else if (tag_stack_test(elem, "types", "registry")) {
  420. return true;
  421. } else if (tag_stack_test(elem, "enums", "registry")) {
  422. enumeration_visitor e(elem);
  423. enumeration *enumeration = e.build();
  424. if (enumeration) {
  425. g_enumerations.push_back(enumeration);
  426. }
  427. return false;
  428. } else if (tag_stack_test(elem, "feature", "registry")) {
  429. const char *supported = elem.Attribute("api");
  430. if (!strcmp(supported, g_api_name)) {
  431. interface *feature = new interface();
  432. float version = elem.FloatAttribute("number");
  433. g_feature_interfaces[(int)roundf(version*10)] = feature;
  434. interface_visitor i_visitor(elem, feature);
  435. elem.Accept(&i_visitor);
  436. }
  437. return false;
  438. } else if (tag_stack_test(elem, "extension", "extensions")) {
  439. const char *api_variant_name = g_variant_name;
  440. const char *supported = elem.Attribute("supported");
  441. char *supported_copy = strdup(supported);
  442. char *token = strtok(supported_copy, "|");
  443. const char *name = elem.Attribute("name") + strlen(g_enumeration_prefix);
  444. //We can't support many SGI extensions due to missing types
  445. if (g_api == API_GLX && (strstr(name, "SGI") == name) && !strstr(name,"swap_control")) {
  446. return false;
  447. }
  448. //No need to support android and it breaks due to missing types
  449. if (g_api == API_EGL && strstr(name, "ANDROID")) {
  450. return false;
  451. }
  452. //Check if this extension is supported by the target API
  453. while (token) {
  454. if (!strcmp(token, g_variant_name)) {
  455. break;
  456. }
  457. token = strtok(NULL, "|");
  458. }
  459. if (token != NULL) {
  460. interface *feature = new interface();
  461. g_extension_interfaces[name] = feature;
  462. interface_visitor i_visitor(elem, feature);
  463. elem.Accept(&i_visitor);
  464. }
  465. return false;
  466. } else if (tag_stack_test(elem, "command", "commands")) {
  467. command_visitor c(elem);
  468. command * command = c.build();
  469. if (command) {
  470. while(command->type_decl.size() > 0 && command->type_decl[command->type_decl.size() - 1] == ' ')
  471. command->type_decl.resize(command->type_decl.size() - 1);
  472. g_commands[command->name] = command;
  473. }
  474. return false;
  475. } else if (tag_stack_test(elem, "type", "types")) {
  476. type_visitor t;
  477. elem.Accept(&t);
  478. return false;
  479. } else {
  480. return false;
  481. }
  482. }
  483. public:
  484. khronos_registry_visitor(XMLDocument &doc) : m_doc(doc) { }
  485. };
  486. void print_interface_declaration(struct interface *iface, FILE *header_file)
  487. {
  488. const char *enumeration_prefix = g_enumeration_prefix;
  489. FOREACH (val, iface->removed_enums, enums_type)
  490. fprintf(header_file, "#undef %s%s\n", enumeration_prefix, *val);
  491. FOREACH (val, iface->enums, enums_type) {
  492. enum_map_type::iterator iter = g_enum_map.find(*val);
  493. fprintf(header_file, "#undef %s%s\n", enumeration_prefix, *val);
  494. if (iter != g_enum_map.end()) {
  495. fprintf(header_file, "#define %s%s 0x%x\n",
  496. enumeration_prefix, *val,
  497. iter->second);
  498. } else {
  499. fprintf(header_file, "#define %s%s %s\n",
  500. enumeration_prefix, *val,
  501. g_enum_str_map[*val]);
  502. }
  503. }
  504. if (iface->enums.size())
  505. indent_fprintf(header_file, "\n");
  506. FOREACH (iter, iface->removed_commands, commands_type) {
  507. command *command = iter->second;
  508. fprintf(header_file, "#undef %s%s\n",
  509. g_command_prefix, command->name);
  510. }
  511. FOREACH (iter, iface->commands, commands_type) {
  512. command *command = iter->second;
  513. fprintf(header_file, "#undef %s%s\n", g_command_prefix, command->name);
  514. fprintf(header_file, "#define %s%s _%s_%s%s\n",
  515. g_command_prefix, command->name,
  516. g_prefix, g_command_prefix, command->name);
  517. command->print_declare(header_file, g_command_prefix);
  518. }
  519. }
  520. void print_interface_definition(struct interface *iface, FILE *source_file)
  521. {
  522. indent_fprintf(source_file, "\n");
  523. FOREACH (iter, iface->commands, commands_type)
  524. iter->second->print_initialize(source_file, g_command_prefix);
  525. }
  526. void interface_append(struct interface *iface, const interface &other)
  527. {
  528. iface->enums.insert(other.enums.begin(), other.enums.end());
  529. FOREACH_CONST (e, other.removed_enums, enums_type)
  530. iface->enums.erase(*e);
  531. iface->commands.insert(other.commands.begin(), other.commands.end());
  532. FOREACH_CONST (iter, other.removed_commands, commands_type)
  533. iface->commands.erase(iter->first);
  534. }
  535. void print_interface_load_check(struct interface *iface, FILE *source_file)
  536. {
  537. if (!iface->commands.size()) {
  538. fprintf(source_file, "true");
  539. } else {
  540. const char *command_prefix = g_command_prefix;
  541. int i = 0;
  542. FOREACH (iter, iface->commands, commands_type) {
  543. if ((i % 3) == 2) {
  544. fprintf(source_file, "\n");
  545. indent_fprintf(source_file, "");
  546. }
  547. if (i)
  548. fprintf(source_file, " && ");
  549. fprintf(source_file, "%s%s", command_prefix, iter->first);
  550. i++;
  551. }
  552. }
  553. }
  554. void bindify(const char *header_name, int min_version, FILE *header_file , FILE *source_file)
  555. {
  556. interface full_interface;
  557. interface base_interface;
  558. int max_version = min_version;
  559. bool is_gl_api = g_api == API_GL;
  560. FOREACH (iter, g_feature_interfaces, feature_interfaces_type) {
  561. if (iter->first <= min_version)
  562. interface_append(&base_interface, *(iter->second));
  563. max_version = iter->first > max_version ? iter->first : max_version;
  564. interface_append(&full_interface,*(iter->second));
  565. }
  566. FOREACH (iter, g_extension_interfaces, extension_interfaces_type) {
  567. interface_append(&full_interface, *(iter->second));
  568. }
  569. fprintf(header_file, "#ifndef GL_BINDIFY_%s_H\n", g_api_name);
  570. fprintf(header_file, "#define GL_BINDIFY_%s_H\n", g_api_name);
  571. fprintf(header_file, "#ifdef __cplusplus\n");
  572. fprintf(header_file, "extern \"C\" {\n");
  573. fprintf(header_file, "#endif\n");
  574. switch (g_api) {
  575. case API_GLX:
  576. fprintf(header_file, "#include <X11/Xlib.h>\n");
  577. fprintf(header_file, "#include <X11/Xutil.h>\n");
  578. break;
  579. case API_WGL:
  580. fprintf(header_file, "#include <windows.h>\n");
  581. break;
  582. }
  583. fprintf(header_file, "#include <stdint.h>\n");
  584. fprintf(header_file, "#include <stddef.h>\n");
  585. fprintf(header_file, "#include <string.h>\n");
  586. fprintf(header_file, "#include <stdbool.h>\n");
  587. //
  588. //We need to include these typedefs even for glx and wgl since they are referenced there without being defined
  589. //
  590. indent_fprintf(header_file, "#ifndef GLBINDIFY_COMMON_GL_TYPEDEFS\n");
  591. indent_fprintf(header_file, "#define GLBINDIFY_COMMON_GL_TYPEDEFS\n");
  592. indent_fprintf(header_file, "typedef unsigned int GLenum;\n");
  593. indent_fprintf(header_file, "typedef unsigned char GLboolean;\n");
  594. indent_fprintf(header_file, "typedef unsigned int GLbitfield;\n");
  595. indent_fprintf(header_file, "typedef signed char GLbyte;\n");
  596. indent_fprintf(header_file, "typedef short GLshort;\n");
  597. indent_fprintf(header_file, "typedef int GLint;\n");
  598. indent_fprintf(header_file, "typedef unsigned char GLubyte;\n");
  599. indent_fprintf(header_file, "typedef unsigned short GLushort;\n");
  600. indent_fprintf(header_file, "typedef unsigned int GLuint;\n");
  601. indent_fprintf(header_file, "typedef int GLsizei;\n");
  602. indent_fprintf(header_file, "typedef float GLfloat;\n");
  603. indent_fprintf(header_file, "typedef double GLdouble;\n");
  604. indent_fprintf(header_file, "typedef ptrdiff_t GLintptr;\n");
  605. indent_fprintf(header_file, "typedef ptrdiff_t GLsizeiptr;\n");
  606. indent_fprintf(header_file, "#endif\n");
  607. indent_fprintf(header_file, "#ifndef %s_%sVERSION\n", g_macro_prefix, g_enumeration_prefix);
  608. indent_fprintf(header_file, "#define %s_%sVERSION %d\n", g_macro_prefix, g_enumeration_prefix, min_version);
  609. indent_fprintf(header_file, "#endif\n");
  610. if (g_api == API_EGL) {
  611. indent_fprintf(header_file, "#include <eglplatform.h>\n");
  612. indent_fprintf(header_file, "#include <khrplatform.h>\n");
  613. }
  614. FOREACH(val, g_types, types_type)
  615. indent_fprintf(header_file, "%s\n", val->c_str());
  616. print_interface_declaration(&base_interface, header_file);
  617. FOREACH (iter, g_feature_interfaces, feature_interfaces_type) {
  618. if (iter->first > min_version) {
  619. indent_fprintf(header_file, "\n");
  620. indent_fprintf(header_file, "#if defined(%s_%sVERSION) && %s_%sVERSION >= %d\n",
  621. g_macro_prefix,
  622. g_enumeration_prefix,
  623. g_macro_prefix,
  624. g_enumeration_prefix,
  625. iter->first);
  626. print_interface_declaration(iter->second, header_file);
  627. indent_fprintf(header_file, "#endif\n");
  628. }
  629. }
  630. indent_fprintf(header_file, "\n");
  631. FOREACH (iter, g_extension_interfaces, extension_interfaces_type) {
  632. indent_fprintf(header_file, "\n");
  633. indent_fprintf(header_file, "#if defined(%s_ENABLE_%s%s)\n", g_macro_prefix, g_enumeration_prefix, iter->first);
  634. indent_fprintf(header_file, "extern bool %s_%s%s;\n", g_macro_prefix, g_enumeration_prefix, iter->first);
  635. print_interface_declaration(iter->second, header_file);
  636. indent_fprintf(header_file, "#endif\n");
  637. }
  638. indent_fprintf(header_file, "\n");
  639. indent_fprintf(header_file, "bool %s_%s_init(int maj, int min);\n", g_prefix, g_variant_name);
  640. indent_fprintf(header_file, "\n");
  641. fprintf(header_file, "#ifdef __cplusplus\n");
  642. fprintf(header_file, "}\n"); //extern "C" {
  643. fprintf(header_file, "#endif\n");
  644. fprintf(header_file, "#endif\n");
  645. reset_indent();
  646. fprintf(source_file, "#ifndef _WIN32\n");
  647. if (g_api != API_EGL && g_api != API_GLX)
  648. fprintf(source_file, "#ifdef %s_USE_EGL\n", g_macro_prefix);
  649. if (g_api != API_GLX) {
  650. fprintf(source_file, "extern void (*eglGetProcAddress(const unsigned char *))(void);\n");
  651. fprintf(source_file, "static inline void *LoadProcAddress(const char *name) { return eglGetProcAddress((const unsigned char *)name); }\n");
  652. }
  653. if (g_api != API_EGL && g_api != API_GLX)
  654. fprintf(source_file, "#else\n");
  655. if (g_api != API_EGL) {
  656. fprintf(source_file, "extern void (*glXGetProcAddress(const unsigned char *))(void);\n");
  657. fprintf(source_file, "static inline void *LoadProcAddress(const char *name) { return glXGetProcAddress((const unsigned char *)name); }\n");
  658. }
  659. if (g_api != API_EGL && g_api != API_GLX)
  660. fprintf(source_file, "#endif\n");
  661. fprintf(source_file, "#include <stdio.h>\n");
  662. fprintf(source_file, "#else\n");
  663. fprintf(source_file, "#include <windows.h>\n");
  664. fprintf(source_file, "#include <wingdi.h>\n");
  665. fprintf(source_file, "#include <stdio.h>\n");
  666. fprintf(source_file, "static PROC LoadProcAddress(const char *name) {\n");
  667. fprintf(source_file, "\tPROC addr = wglGetProcAddress((LPCSTR)name);\n");
  668. fprintf(source_file, "\tif (addr) return addr;\n");
  669. fprintf(source_file, "\telse return (PROC)GetProcAddress(GetModuleHandleA(\"OpenGL32.dll\"), (LPCSTR)name);\n");
  670. fprintf(source_file, "}\n");
  671. fprintf(source_file, "#endif\n");
  672. fprintf(source_file, "#define %s_%sVERSION %d\n", g_macro_prefix, g_enumeration_prefix, max_version);
  673. FOREACH (iter, g_extension_interfaces, extension_interfaces_type) {
  674. indent_fprintf(source_file, "#undef %s_ENABLE_%s%s\n", g_macro_prefix, g_enumeration_prefix, iter->first);
  675. indent_fprintf(source_file, "#define %s_ENABLE_%s%s\n", g_macro_prefix, g_enumeration_prefix, iter->first);
  676. }
  677. fprintf(source_file, "#include \"%s\"\n", header_name);
  678. print_interface_definition(&full_interface, source_file);
  679. indent_fprintf(source_file, "\n");
  680. FOREACH (iter, g_extension_interfaces, extension_interfaces_type) {
  681. indent_fprintf(source_file, "bool %s_%s%s = %s;\n",
  682. g_macro_prefix,
  683. g_enumeration_prefix,
  684. iter->first,
  685. is_gl_api ? "false" : "true");
  686. }
  687. #if USE_GPERF
  688. if (is_gl_api) {
  689. //
  690. // Have gperf make a hash table for extension names. We can write the output
  691. // directly to source file
  692. //
  693. fflush(source_file);
  694. int fdpair[2];
  695. int rc = pipe(fdpair);
  696. if (rc) {
  697. fprintf(stderr, "pipe() failed: %s. Aborting...\n", strerror(errno));
  698. }
  699. pid_t child_pid = fork();
  700. if (child_pid) {
  701. int status;
  702. pid_t pid;
  703. close(fdpair[0]);
  704. FILE *gperf_in = fdopen(fdpair[1], "w");
  705. fprintf(gperf_in, "%%struct-type\n");
  706. fprintf(gperf_in, "%%define lookup-function-name %s_find_extension\n", g_prefix);
  707. fprintf(gperf_in, "%%define initializer-suffix ,NULL\n");
  708. fprintf(gperf_in, "struct extension_match { const char *name; bool *support_flag; };\n");
  709. fprintf(gperf_in, "%%%%\n");
  710. FOREACH (iter, g_extension_interfaces, extension_interfaces_type) {
  711. fprintf(gperf_in, "%s%s, &%s_%s%s\n", g_enumeration_prefix, iter->first,
  712. g_macro_prefix, g_enumeration_prefix, iter->first);
  713. }
  714. fflush(gperf_in);
  715. close(fdpair[1]);
  716. pid = waitpid(child_pid, &status, 0);
  717. if (pid != child_pid || WEXITSTATUS(status)) {
  718. fprintf(stderr, "Error encountered while running gperf\n");
  719. exit(-1);
  720. }
  721. } else {
  722. close(fdpair[1]);
  723. dup2(fdpair[0], STDIN_FILENO);
  724. dup2(fileno(source_file), STDOUT_FILENO);
  725. execlp("gperf", "gperf", 0);
  726. }
  727. }
  728. #endif
  729. indent_fprintf(source_file, "\n");
  730. indent_fprintf(source_file, "bool %s_%s_init(int maj, int min)\n", g_prefix, g_variant_name);
  731. indent_fprintf(source_file, "{\n");
  732. increase_indent();
  733. indent_fprintf(source_file, "int req_version = maj * 10 + min;\n");
  734. if (is_gl_api) {
  735. indent_fprintf(source_file, "int actual_maj, actual_min, actual_version, i;\n");
  736. indent_fprintf(source_file, "int num_extensions;\n");
  737. }
  738. indent_fprintf(source_file, "if (req_version < %d) return false;\n", min_version);
  739. indent_fprintf(source_file, "if (req_version > %d) return false;\n", max_version);
  740. FOREACH (iter, full_interface.commands, commands_type)
  741. (iter->second)->print_load(source_file, g_command_prefix);
  742. if (is_gl_api) {
  743. indent_fprintf(source_file, "\n");
  744. indent_fprintf(source_file, "if (!glGetIntegerv || !glGetStringi) return false;\n");
  745. indent_fprintf(source_file, "glGetIntegerv(GL_NUM_EXTENSIONS, &num_extensions);\n");
  746. indent_fprintf(source_file, "glGetIntegerv(GL_MAJOR_VERSION, &actual_maj);\n");
  747. indent_fprintf(source_file, "glGetIntegerv(GL_MINOR_VERSION, &actual_min);\n");
  748. indent_fprintf(source_file, "actual_version = actual_maj * 10 + actual_min;\n");
  749. indent_fprintf(source_file, "if (actual_version < req_version) return false;\n");
  750. indent_fprintf(source_file, "for (i = 0; i < num_extensions; i++) {\n");
  751. indent_fprintf(source_file, "\tconst char *extname = (const char *)glGetStringi(GL_EXTENSIONS, i);\n");
  752. #if USE_GPERF
  753. indent_fprintf(source_file, "\tstruct extension_match *match = %s_find_extension(extname, strlen(extname));\n", g_prefix);
  754. indent_fprintf(source_file, "\tif (match)\n");
  755. indent_fprintf(source_file, "\t\t*match->support_flag = true;\n");
  756. #else
  757. FOREACH (iter, g_extension_interfaces, extension_interfaces_type) {
  758. indent_fprintf(source_file, "\tif (!strcmp(extname, \"%s%s\")) {\n", g_enumeration_prefix, iter->first);
  759. indent_fprintf(source_file, "\t\t%s_%s%s = true;\n", g_macro_prefix, g_enumeration_prefix, iter->first);
  760. indent_fprintf(source_file, "\t\tcontinue;\n");
  761. indent_fprintf(source_file, "\t}\n");
  762. }
  763. #endif
  764. indent_fprintf(source_file, "}\n");
  765. }
  766. FOREACH (iter, g_extension_interfaces, extension_interfaces_type) {
  767. if (iter->second->commands.size()) {
  768. indent_fprintf(source_file, "\n");
  769. indent_fprintf(source_file, "%s_%s%s = %s_%s%s && ",
  770. g_macro_prefix, g_enumeration_prefix, iter->first,
  771. g_macro_prefix, g_enumeration_prefix, iter->first);
  772. increase_indent();
  773. print_interface_load_check(iter->second, source_file);
  774. decrease_indent();
  775. fprintf(source_file, ";\n");
  776. }
  777. }
  778. indent_fprintf(source_file, "\n");
  779. indent_fprintf(source_file, "return ");
  780. print_interface_load_check(&base_interface, source_file);
  781. FOREACH(iter, g_feature_interfaces, feature_interfaces_type) {
  782. if (iter->first <= min_version || !iter->second->commands.size())
  783. continue;
  784. fprintf(source_file, "\n");
  785. indent_fprintf(source_file, " && ((req_version < %d) ||\n", iter->first);
  786. increase_indent();
  787. indent_fprintf(source_file, "(");
  788. print_interface_load_check(iter->second, source_file);
  789. fprintf(source_file, "))");
  790. decrease_indent();
  791. }
  792. fprintf(source_file, ";\n");
  793. decrease_indent();
  794. indent_fprintf(source_file, "}\n"); //init()
  795. }
  796. static void print_help(const char *program_name)
  797. {
  798. printf("Usage: %s [OPTION]...\n", program_name);
  799. printf("\n"
  800. "Options:\n"
  801. " -a,--api <api> Generate bindings for API <api>. Must be one\n"
  802. " of 'gl', 'wgl', 'egl', 'gles2', or 'glx'. Default is 'gl'\n"
  803. " -n,--namespace <Namespace> Namespace for generated bindings. This is the first\n"
  804. " part of the name of every function and macro.\n"
  805. " -s,--srcdir <dir> Directory to find XML sources\n"
  806. " -v,--version Print version information\n"
  807. " -h,--help Display this page\n");
  808. }
  809. int main(int argc, char **argv)
  810. {
  811. XMLDocument doc;
  812. XMLError err;
  813. g_common_gl_typedefs.insert("GLenum");
  814. g_common_gl_typedefs.insert("GLboolean");
  815. g_common_gl_typedefs.insert("GLbitfield");
  816. g_common_gl_typedefs.insert("GLbyte");
  817. g_common_gl_typedefs.insert("GLshort");
  818. g_common_gl_typedefs.insert("GLint");
  819. g_common_gl_typedefs.insert("GLubyte");
  820. g_common_gl_typedefs.insert("GLushort");
  821. g_common_gl_typedefs.insert("GLuint");
  822. g_common_gl_typedefs.insert("GLsizei");
  823. g_common_gl_typedefs.insert("GLfloat");
  824. g_common_gl_typedefs.insert("GLdouble");
  825. g_common_gl_typedefs.insert("GLintptr");
  826. g_common_gl_typedefs.insert("GLsizeiptr");
  827. static struct option options [] = {
  828. {"api" , 1, 0, 'a' },
  829. {"srcdir" , 1, 0, 's' },
  830. {"version" , 1, 0, 'v' },
  831. {"namespace" , 0, 0, 'n' },
  832. {"help" , 0, 0, 'h' }
  833. };
  834. g_api_name = "gl";
  835. const char *srcdir = NULL;
  836. const char *prefix = "glb";
  837. char *macro_prefix;
  838. while (1) {
  839. int option_index;
  840. int c = getopt_long(argc, argv, "a:s:n:v", options, &option_index);
  841. if (c == -1) {
  842. break;
  843. }
  844. switch (c) {
  845. case '?':
  846. case ':':
  847. print_help(argv[0]);
  848. exit(-1);
  849. break;
  850. case 'v':
  851. printf("glbindify version %s\n", PACKAGE_VERSION);
  852. exit(0);
  853. break;
  854. case 'a':
  855. g_api_name = optarg;
  856. break;
  857. case 's':
  858. srcdir = optarg;
  859. break;
  860. case 'n':
  861. prefix = optarg;
  862. break;
  863. case 'h':
  864. print_help(argv[0]);
  865. exit(0);
  866. break;
  867. }
  868. }
  869. macro_prefix = strdup(prefix);
  870. int i;
  871. for (i = 0; macro_prefix[i]; i++) {
  872. macro_prefix[i] = toupper(macro_prefix[i]);
  873. }
  874. g_prefix = prefix;
  875. g_macro_prefix = macro_prefix;
  876. printf("Generating bindings for %s with namespace '%s'\n", g_api_name, g_prefix);
  877. const char *xml_name = NULL;
  878. if (!strcmp(g_api_name, "wgl")) {
  879. g_api = API_WGL;
  880. g_command_prefix = "wgl";
  881. g_enumeration_prefix = "WGL_";
  882. g_api_print_name = "WGL";
  883. g_variant_name = g_api_name;
  884. xml_name = "wgl.xml";
  885. } else if (!strcmp(g_api_name, "glx")) {
  886. g_api = API_GLX;
  887. g_command_prefix = "glX";
  888. g_enumeration_prefix = "GLX_";
  889. g_variant_name = g_api_name;
  890. xml_name = "glx.xml";
  891. g_api_print_name = "glX";
  892. } else if (!strcmp(g_api_name, "gl")) {
  893. g_api = API_GL;
  894. g_command_prefix = "gl";
  895. g_enumeration_prefix = "GL_";
  896. g_api_print_name = "OpenGL";
  897. g_variant_name = "glcore";
  898. xml_name = "gl.xml";
  899. } else if (!strcmp(g_api_name, "egl")) {
  900. g_api = API_EGL;
  901. g_command_prefix = "egl";
  902. g_enumeration_prefix = "EGL_";
  903. g_api_print_name = "EGL";
  904. g_variant_name = g_api_name;
  905. xml_name = "egl.xml";
  906. } else if (!strcmp(g_api_name, "gles2")) {
  907. g_api = API_GLES2;
  908. g_command_prefix = "gl";
  909. g_enumeration_prefix = "GL_";
  910. g_api_print_name = "GLES2";
  911. g_variant_name = g_api_name;
  912. xml_name = "gl.xml";
  913. } else {
  914. fprintf(stderr, "Unrecognized API '%s'\n", g_api_name);
  915. print_help(argv[0]);
  916. exit(-1);
  917. }
  918. char in_filename[200];
  919. #ifdef PKGDATADIR
  920. if (!srcdir) {
  921. srcdir = PKGDATADIR;
  922. }
  923. snprintf(in_filename, sizeof(in_filename), "%s/%s", srcdir, xml_name);
  924. #else
  925. if (!srcdir) {
  926. srcdir = ".";
  927. }
  928. snprintf(in_filename, sizeof(in_filename), "%s/%s", srcdir, xml_name);
  929. #endif
  930. err = doc.LoadFile(in_filename);
  931. if (err != XML_NO_ERROR) {
  932. fprintf(stderr, "Error loading khronos registry file %s\n", in_filename);
  933. exit(-1);
  934. }
  935. char header_name[100];
  936. char c_name[100];
  937. snprintf(header_name, sizeof(header_name), "%s.h", g_variant_name);
  938. snprintf(c_name, sizeof(c_name), "%s.c", g_variant_name);
  939. FILE *header_file = fopen(header_name, "w+");
  940. if (!header_file) {
  941. fprintf(stderr, "Error creating header file '%s': %s\n", header_name, strerror(errno));
  942. exit(-1);
  943. }
  944. FILE *source_file = fopen(c_name, "w+");
  945. if (!source_file) {
  946. fprintf(stderr, "Error creating source file '%s': %s\n", c_name, strerror(errno));
  947. exit(-1);
  948. }
  949. printf("Writing bindings to %s and %s\n", c_name, header_name);
  950. khronos_registry_visitor registry_visitor(doc);
  951. doc.Accept(&registry_visitor);
  952. fprintf(source_file, "/* C %s bindings generated by %s */\n", g_api_print_name, PACKAGE_STRING);
  953. fprintf(header_file, "/* C %s bindings generated by %s */\n", g_api_print_name, PACKAGE_STRING);
  954. fprintf(source_file, "/* Command line: ");
  955. fprintf(header_file, "/* Command line: ");
  956. for (i = 0; i < argc; i++) {
  957. fprintf(source_file, "%s ", argv[i]);
  958. fprintf(header_file, "%s ", argv[i]);
  959. }
  960. fprintf(source_file, "*/\n\n");
  961. fprintf(header_file, "*/\n\n");
  962. int min_ver = 10;
  963. switch (g_api) {
  964. case API_GL:
  965. min_ver = 32;
  966. break;
  967. case API_GLX:
  968. min_ver = 14;
  969. break;
  970. case API_GLES2:
  971. min_ver = 20;
  972. break;
  973. }
  974. bindify(header_name, min_ver, header_file, source_file);
  975. fclose(source_file);
  976. fclose(header_file);
  977. return 0;
  978. }