2
0

ConfigSet.cpp 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. // Copyright (C) 2009-2023, Panagiotis Christopoulos Charitos and contributors.
  2. // All rights reserved.
  3. // Code licensed under the BSD License.
  4. // http://www.anki3d.org/LICENSE
  5. #include <AnKi/Core/ConfigSet.h>
  6. #include <AnKi/Util/Xml.h>
  7. #include <AnKi/Util/Logger.h>
  8. #include <AnKi/Util/File.h>
  9. // Because some cvars set their default values
  10. #include <AnKi/Util/System.h>
  11. #include <AnKi/Shaders/Include/ClusteredShadingTypes.h>
  12. namespace anki {
  13. ConfigSet::~ConfigSet()
  14. {
  15. #define ANKI_CONFIG_VAR_STRING(name, defaultValue, description) \
  16. if(m_##name.m_value) \
  17. { \
  18. m_pool.free(m_##name.m_value); \
  19. }
  20. #include <AnKi/Core/AllConfigVars.defs.h>
  21. #if ANKI_EXTRA_CHECKS
  22. for(const Var& var : m_vars)
  23. {
  24. if(var.m_timesAccessed.load() == 0)
  25. {
  26. ANKI_CORE_LOGW("Config var doesn't appear to have been accessed. Maybe unused: %s", var.m_name.cstr());
  27. }
  28. }
  29. #endif
  30. }
  31. void ConfigSet::init(AllocAlignedCallback allocCb, void* allocCbUserData)
  32. {
  33. ANKI_ASSERT(!isInitialized());
  34. m_pool.init(allocCb, allocCbUserData);
  35. #define ANKI_CONFIG_VAR_NUMERIC(name, defaultValue, minValue, maxValue, description) \
  36. ANKI_ASSERT((minValue) <= (maxValue) && (defaultValue) >= (minValue) && (defaultValue) <= (maxValue)); \
  37. m_##name.m_name = #name; \
  38. m_##name.m_description = description; \
  39. m_##name.m_value = defaultValue; \
  40. m_##name.m_min = minValue; \
  41. m_##name.m_max = maxValue; \
  42. m_vars.pushBack(&m_##name);
  43. #define ANKI_CONFIG_VAR_U8(name, defaultValue, minValue, maxValue, description) \
  44. ANKI_CONFIG_VAR_NUMERIC(name, defaultValue, minValue, maxValue, description)
  45. #define ANKI_CONFIG_VAR_U32(name, defaultValue, minValue, maxValue, description) \
  46. ANKI_CONFIG_VAR_NUMERIC(name, defaultValue, minValue, maxValue, description)
  47. #define ANKI_CONFIG_VAR_PTR_SIZE(name, defaultValue, minValue, maxValue, description) \
  48. ANKI_CONFIG_VAR_NUMERIC(name, defaultValue, minValue, maxValue, description)
  49. #define ANKI_CONFIG_VAR_F32(name, defaultValue, minValue, maxValue, description) \
  50. ANKI_CONFIG_VAR_NUMERIC(name, defaultValue, minValue, maxValue, description)
  51. #define ANKI_CONFIG_VAR_BOOL(name, defaultValue, description) \
  52. m_##name.m_name = #name; \
  53. m_##name.m_description = description; \
  54. m_##name.m_value = defaultValue; \
  55. m_vars.pushBack(&m_##name);
  56. #define ANKI_CONFIG_VAR_STRING(name, defaultValue, description) \
  57. m_##name.m_name = #name; \
  58. m_##name.m_description = description; \
  59. setStringVar(defaultValue, m_##name); \
  60. m_vars.pushBack(&m_##name);
  61. #include <AnKi/Core/AllConfigVars.defs.h>
  62. }
  63. ConfigSet::Var* ConfigSet::tryFind(CString optionName)
  64. {
  65. for(auto it = m_vars.getBegin(); it != m_vars.getEnd(); ++it)
  66. {
  67. if((*it).m_name == optionName)
  68. {
  69. return &(*it);
  70. }
  71. }
  72. return nullptr;
  73. }
  74. const ConfigSet::Var* ConfigSet::tryFind(CString optionName) const
  75. {
  76. for(auto it = m_vars.getBegin(); it != m_vars.getEnd(); ++it)
  77. {
  78. if((*it).m_name == optionName)
  79. {
  80. return &(*it);
  81. }
  82. }
  83. return nullptr;
  84. }
  85. Error ConfigSet::loadFromFile(CString filename)
  86. {
  87. ANKI_ASSERT(isInitialized());
  88. ANKI_CORE_LOGI("Loading config file %s", filename.cstr());
  89. CoreXmlDocument xml;
  90. ANKI_CHECK(xml.loadFile(filename));
  91. XmlElement rootel;
  92. ANKI_CHECK(xml.getChildElement("config", rootel));
  93. XmlElement el;
  94. #define ANKI_NUMERIC(name) \
  95. ANKI_CHECK(rootel.getChildElementOptional(m_##name.m_name, el)); \
  96. if(el) \
  97. { \
  98. ANKI_CHECK(el.getNumber(m_##name.m_value)); \
  99. }
  100. #define ANKI_CONFIG_VAR_U8(name, defaultValue, minValue, maxValue, description) ANKI_NUMERIC(name)
  101. #define ANKI_CONFIG_VAR_U32(name, defaultValue, minValue, maxValue, description) ANKI_NUMERIC(name)
  102. #define ANKI_CONFIG_VAR_PTR_SIZE(name, defaultValue, minValue, maxValue, description) ANKI_NUMERIC(name)
  103. #define ANKI_CONFIG_VAR_F32(name, defaultValue, minValue, maxValue, description) ANKI_NUMERIC(name)
  104. #define ANKI_CONFIG_VAR_BOOL(name, defaultValue, description) \
  105. ANKI_CHECK(rootel.getChildElementOptional(m_##name.m_name, el)); \
  106. if(el) \
  107. { \
  108. CString txt; \
  109. ANKI_CHECK(el.getText(txt)); \
  110. if(txt == "true") \
  111. { \
  112. m_##name.m_value = true; \
  113. } \
  114. else if(txt == "false") \
  115. { \
  116. m_##name.m_value = false; \
  117. } \
  118. else \
  119. { \
  120. ANKI_CORE_LOGE("Wrong value for %s", m_##name.m_name.cstr()); \
  121. return Error::kUserData; \
  122. } \
  123. }
  124. #define ANKI_CONFIG_VAR_STRING(name, defaultValue, description) \
  125. ANKI_CHECK(rootel.getChildElementOptional(m_##name.m_name, el)); \
  126. if(el) \
  127. { \
  128. CString txt; \
  129. ANKI_CHECK(el.getText(txt)); \
  130. setStringVar(txt, m_##name); \
  131. }
  132. #include <AnKi/Core/AllConfigVars.defs.h>
  133. #undef ANKI_NUMERIC
  134. return Error::kNone;
  135. }
  136. Error ConfigSet::saveToFile(CString filename) const
  137. {
  138. ANKI_ASSERT(isInitialized());
  139. ANKI_CORE_LOGI("Saving config file %s", &filename[0]);
  140. File file;
  141. ANKI_CHECK(file.open(filename, FileOpenFlag::kWrite));
  142. ANKI_CHECK(file.writeTextf("%s\n<config>\n", CoreXmlDocument::kXmlHeader.cstr()));
  143. #define ANKI_NUMERIC_UINT(name) \
  144. ANKI_CHECK(file.writeTextf("\t<!-- %s -->\n", m_##name.m_description.cstr())); \
  145. ANKI_CHECK(file.writeTextf("\t<%s>%" PRIu64 "</%s>\n", m_##name.m_name.cstr(), U64(m_##name.m_value), m_##name.m_name.cstr()));
  146. #define ANKI_CONFIG_VAR_U8(name, defaultValue, minValue, maxValue, description) ANKI_NUMERIC_UINT(name)
  147. #define ANKI_CONFIG_VAR_U32(name, defaultValue, minValue, maxValue, description) ANKI_NUMERIC_UINT(name)
  148. #define ANKI_CONFIG_VAR_PTR_SIZE(name, defaultValue, minValue, maxValue, description) ANKI_NUMERIC_UINT(name)
  149. #define ANKI_CONFIG_VAR_F32(name, defaultValue, minValue, maxValue, description) ANKI_NUMERIC_UINT(name)
  150. #define ANKI_CONFIG_VAR_BOOL(name, defaultValue, description) \
  151. ANKI_CHECK(file.writeTextf("\t<!-- %s -->\n", m_##name.m_description.cstr())); \
  152. ANKI_CHECK(file.writeTextf("\t<%s>%s</%s>\n", m_##name.m_name.cstr(), (m_##name.m_value) ? "true" : "false", m_##name.m_name.cstr()));
  153. #define ANKI_CONFIG_VAR_STRING(name, defaultValue, description) \
  154. ANKI_CHECK(file.writeTextf("\t<!-- %s -->\n", m_##name.m_description.cstr())); \
  155. ANKI_CHECK(file.writeTextf("\t<%s>%s</%s>\n", m_##name.m_name.cstr(), m_##name.m_value, m_##name.m_name.cstr()));
  156. #include <AnKi/Core/AllConfigVars.defs.h>
  157. #undef ANKI_NUMERIC_UINT
  158. ANKI_CHECK(file.writeText("</config>\n"));
  159. return Error::kNone;
  160. }
  161. Error ConfigSet::setFromCommandLineArguments(U32 cmdLineArgsCount, char* cmdLineArgs[])
  162. {
  163. ANKI_ASSERT(isInitialized());
  164. for(U i = 0; i < cmdLineArgsCount; ++i)
  165. {
  166. ANKI_ASSERT(cmdLineArgs[i]);
  167. const CString varName = cmdLineArgs[i];
  168. // Set the value
  169. ++i;
  170. if(i >= cmdLineArgsCount)
  171. {
  172. ANKI_CORE_LOGE("Expecting a command line argument after %s", varName.cstr());
  173. return Error::kUserData;
  174. }
  175. ANKI_ASSERT(cmdLineArgs[i]);
  176. const CString value = cmdLineArgs[i];
  177. if(false)
  178. {
  179. }
  180. #define ANKI_NUMERIC(type, name) \
  181. else if(varName == m_##name.m_name) \
  182. { \
  183. type v; \
  184. ANKI_CHECK(value.toNumber(v)); \
  185. set##name(v); \
  186. }
  187. #define ANKI_CONFIG_VAR_U8(name, defaultValue, minValue, maxValue, description) ANKI_NUMERIC(U8, name)
  188. #define ANKI_CONFIG_VAR_U32(name, defaultValue, minValue, maxValue, description) ANKI_NUMERIC(U32, name)
  189. #define ANKI_CONFIG_VAR_PTR_SIZE(name, defaultValue, minValue, maxValue, description) ANKI_NUMERIC(PtrSize, name)
  190. #define ANKI_CONFIG_VAR_F32(name, defaultValue, minValue, maxValue, description) ANKI_NUMERIC(F32, name)
  191. #define ANKI_CONFIG_VAR_BOOL(name, defaultValue, description) \
  192. else if(varName == m_##name.m_name) \
  193. { \
  194. U32 v; \
  195. ANKI_CHECK(value.toNumber(v)); \
  196. m_##name.m_value = v != 0; \
  197. }
  198. #define ANKI_CONFIG_VAR_STRING(name, defaultValue, description) \
  199. else if(varName == m_##name.m_name) \
  200. { \
  201. setStringVar(value, m_##name); \
  202. }
  203. #include <AnKi/Core/AllConfigVars.defs.h>
  204. #undef ANKI_NUMERIC
  205. else
  206. {
  207. ANKI_CORE_LOGW("Can't recognize command line argument: %s. Skipping", varName.cstr());
  208. }
  209. }
  210. return Error::kNone;
  211. }
  212. } // end namespace anki