PageRenderTime 61ms CodeModel.GetById 30ms RepoModel.GetById 1ms app.codeStats 0ms

/include/oglplus/error.hpp

https://github.com/MaikKlein/oglplus
C++ Header | 1297 lines | 831 code | 120 blank | 346 comment | 37 complexity | 496e580ece398b458fcbf378d3798d8b MD5 | raw file
  1. /**
  2. * @file oglplus/error.hpp
  3. * @brief Declaration of OGLplus' exceptions
  4. *
  5. * @author Matus Chochlik
  6. *
  7. * Copyright 2010-2013 Matus Chochlik. Distributed under the Boost
  8. * Software License, Version 1.0. (See accompanying file
  9. * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  10. */
  11. #pragma once
  12. #ifndef OGLPLUS_ERROR_1107121317_HPP
  13. #define OGLPLUS_ERROR_1107121317_HPP
  14. #include <oglplus/auxiliary/strings.hpp>
  15. #include <oglplus/config.hpp>
  16. #include <stdexcept>
  17. #include <cassert>
  18. #include <list>
  19. #include <map>
  20. #if OGLPLUS_CUSTOM_ERROR_HANDLING
  21. #include <stack>
  22. #include <functional>
  23. #endif
  24. #define OGLPLUS_ERROR_INFO_CONTEXT(CONTEXT, CLASS) \
  25. static const char* _errinf_ctxt(void) \
  26. { \
  27. return #CONTEXT; \
  28. } \
  29. static const char* _errinf_cls(void) \
  30. { \
  31. return #CLASS; \
  32. }
  33. #define OGLPLUS_ERROR_INFO_REUSE_CONTEXT(SOURCE) \
  34. using SOURCE::_errinf_ctxt; \
  35. using SOURCE::_errinf_cls;
  36. // Define a macro that initializes the _glsym member of ErrorInfo
  37. #if OGLPLUS_ERROR_INFO_NO_GL_SYMBOL
  38. #define OGLPLUS_ERROR_INFO_INIT_GLSYM(SYMBOL)
  39. #else
  40. #define OGLPLUS_ERROR_INFO_INIT_GLSYM(SYMBOL) , SYMBOL
  41. #endif
  42. // Define a macro that initializes the _file member of ErrorInfo
  43. #if OGLPLUS_ERROR_INFO_NO_FILE
  44. #define OGLPLUS_ERROR_INFO_INIT_FILE(FILEPATH)
  45. #else
  46. #define OGLPLUS_ERROR_INFO_INIT_FILE(FILEPATH) , FILEPATH
  47. #endif
  48. // Define a macro that initializes the _func member of ErrorInfo
  49. #if OGLPLUS_ERROR_INFO_NO_FUNC
  50. #define OGLPLUS_ERROR_INFO_INIT_FUNC(FUNC)
  51. #else
  52. #define OGLPLUS_ERROR_INFO_INIT_FUNC(FUNC) , FUNC
  53. #endif
  54. // Define a macro that initializes the _line member of ErrorInfo
  55. #if OGLPLUS_ERROR_INFO_NO_LINE
  56. #define OGLPLUS_ERROR_INFO_INIT_LINE(LINE)
  57. #else
  58. #define OGLPLUS_ERROR_INFO_INIT_LINE(LINE) , LINE
  59. #endif
  60. // Define a macro that initializes the _cls_name member of ErrorInfo
  61. #if OGLPLUS_ERROR_INFO_NO_CLASS_NAME
  62. #define OGLPLUS_ERROR_INFO_INIT_CLS_NAME(NAME)
  63. #else
  64. #define OGLPLUS_ERROR_INFO_INIT_CLS_NAME(NAME) , NAME
  65. #endif
  66. // Define a macro that initializes the _bind_tgt member of ErrorInfo
  67. #if OGLPLUS_ERROR_INFO_NO_BIND_TARGET
  68. #define OGLPLUS_ERROR_INFO_INIT_BIND_TGT(NAME)
  69. #else
  70. #define OGLPLUS_ERROR_INFO_INIT_BIND_TGT(NAME) , NAME
  71. #endif
  72. // Define a macro that initializes the description-related members of ErrorInfo
  73. #if OGLPLUS_ERROR_INFO_NO_OBJECT_DESC
  74. #define OGLPLUS_ERROR_INFO_INIT_OBJ_DECS_FUNCS(GET, PURGE, NAME)
  75. #else
  76. #define OGLPLUS_ERROR_INFO_INIT_OBJ_DECS_FUNCS(GET, PURGE, NAME) \
  77. , GET, PURGE, GLuint(NAME)
  78. #endif
  79. #define OGLPLUS_ERROR_INFO(CONTEXT) \
  80. oglplus::ErrorInfo(\
  81. sizeof(decltype(&gl ## CONTEXT)) \
  82. OGLPLUS_ERROR_INFO_INIT_GLSYM(#CONTEXT) \
  83. OGLPLUS_ERROR_INFO_INIT_FILE(__FILE__) \
  84. OGLPLUS_ERROR_INFO_INIT_FUNC(__FUNCTION__) \
  85. OGLPLUS_ERROR_INFO_INIT_LINE(__LINE__) \
  86. OGLPLUS_ERROR_INFO_INIT_CLS_NAME("") \
  87. OGLPLUS_ERROR_INFO_INIT_BIND_TGT(StrLit()) \
  88. OGLPLUS_ERROR_INFO_INIT_OBJ_DECS_FUNCS(nullptr, nullptr, 0) \
  89. )
  90. #define OGLPLUS_LIMIT_ERROR_INFO(CONTEXT) \
  91. oglplus::ErrorInfo(\
  92. sizeof(decltype(GL_ ## CONTEXT)) \
  93. OGLPLUS_ERROR_INFO_INIT_GLSYM(#CONTEXT) \
  94. OGLPLUS_ERROR_INFO_INIT_FILE(__FILE__) \
  95. OGLPLUS_ERROR_INFO_INIT_FUNC(__FUNCTION__) \
  96. OGLPLUS_ERROR_INFO_INIT_LINE(__LINE__) \
  97. OGLPLUS_ERROR_INFO_INIT_CLS_NAME("") \
  98. OGLPLUS_ERROR_INFO_INIT_BIND_TGT(StrLit()) \
  99. OGLPLUS_ERROR_INFO_INIT_OBJ_DECS_FUNCS(nullptr, nullptr, 0) \
  100. )
  101. #define OGLPLUS_ERROR_INFO_AUTO_CTXT() \
  102. oglplus::ErrorInfo(\
  103. 0 \
  104. OGLPLUS_ERROR_INFO_INIT_GLSYM(_errinf_ctxt()) \
  105. OGLPLUS_ERROR_INFO_INIT_FILE(__FILE__) \
  106. OGLPLUS_ERROR_INFO_INIT_FUNC(__FUNCTION__) \
  107. OGLPLUS_ERROR_INFO_INIT_LINE(__LINE__) \
  108. OGLPLUS_ERROR_INFO_INIT_CLS_NAME(_errinf_cls()) \
  109. OGLPLUS_ERROR_INFO_INIT_BIND_TGT(StrLit()) \
  110. OGLPLUS_ERROR_INFO_INIT_OBJ_DECS_FUNCS(nullptr, nullptr, 0) \
  111. )
  112. #define OGLPLUS_ERROR_INFO_STR(CONTEXT_STR) \
  113. oglplus::ErrorInfo(\
  114. 0 \
  115. OGLPLUS_ERROR_INFO_INIT_GLSYM(CONTEXT_STR) \
  116. OGLPLUS_ERROR_INFO_INIT_FILE(__FILE__) \
  117. OGLPLUS_ERROR_INFO_INIT_FUNC(__FUNCTION__) \
  118. OGLPLUS_ERROR_INFO_INIT_LINE(__LINE__) \
  119. OGLPLUS_ERROR_INFO_INIT_CLS_NAME("") \
  120. OGLPLUS_ERROR_INFO_INIT_BIND_TGT(StrLit()) \
  121. OGLPLUS_ERROR_INFO_INIT_OBJ_DECS_FUNCS(nullptr, nullptr, 0) \
  122. )
  123. #define OGLPLUS_OBJECT_ERROR_INFO(CONTEXT, CLASS, TARGET_NAME, NAME) \
  124. oglplus::ErrorInfo(\
  125. sizeof(decltype(&gl ## CONTEXT)) \
  126. OGLPLUS_ERROR_INFO_INIT_GLSYM(#CONTEXT) \
  127. OGLPLUS_ERROR_INFO_INIT_FILE(__FILE__) \
  128. OGLPLUS_ERROR_INFO_INIT_FUNC(__FUNCTION__) \
  129. OGLPLUS_ERROR_INFO_INIT_LINE(__LINE__) \
  130. OGLPLUS_ERROR_INFO_INIT_CLS_NAME(#CLASS) \
  131. OGLPLUS_ERROR_INFO_INIT_BIND_TGT(TARGET_NAME) \
  132. OGLPLUS_ERROR_INFO_INIT_OBJ_DECS_FUNCS( \
  133. &oglplus::aux::ObjectDescRegistry<CLASS##Ops>::_get_desc, \
  134. &oglplus::aux::ObjectDescRegistry<CLASS##Ops>::_purge_archive,\
  135. NAME \
  136. ) \
  137. )
  138. namespace oglplus {
  139. /** @defgroup error_handling Error handling
  140. *
  141. * The exception classes listed below provide information about errors
  142. * that occur during the excecution of the OpenGL function calls in the
  143. * @OGLplus wrappers.
  144. */
  145. /// Basic information about exception's throw site and propagation trace points
  146. /**
  147. * @see ErrorGLSymbol
  148. * @see ErrorFunc
  149. * @see ErrorFile
  150. * @see ErrorLine
  151. * @see ErrorObjectDescription
  152. *
  153. * @ingroup error_handling
  154. */
  155. struct ErrorInfo
  156. {
  157. // the data members of this structure are internal
  158. // implementation details which are subject to change
  159. // without any prior notice. Do not use directly.
  160. const size_t _dummy;
  161. #if !OGLPLUS_ERROR_INFO_NO_GL_SYMBOL
  162. const char* _glsym;
  163. #endif
  164. #if !OGLPLUS_ERROR_INFO_NO_FILE
  165. const char* _file;
  166. #endif
  167. #if !OGLPLUS_ERROR_INFO_NO_FUNC
  168. const char* _func;
  169. #endif
  170. #if !OGLPLUS_ERROR_INFO_NO_LINE
  171. const unsigned _line;
  172. #endif
  173. #if !OGLPLUS_ERROR_INFO_NO_CLASS_NAME
  174. const char* _cls_name;
  175. #endif
  176. #if !OGLPLUS_ERROR_INFO_NO_BIND_TARGET
  177. const StrLit _bind_tgt;
  178. #endif
  179. #if !OGLPLUS_ERROR_INFO_NO_OBJECT_DESC
  180. const String& (*_get_obj_desc)(GLuint);
  181. void (*_purge_archive)(void);
  182. GLuint _obj_name;
  183. #endif
  184. inline ErrorInfo(
  185. const size_t dummy
  186. #if !OGLPLUS_ERROR_INFO_NO_GL_SYMBOL
  187. , const char* glsym
  188. #endif
  189. #if !OGLPLUS_ERROR_INFO_NO_FILE
  190. , const char* file
  191. #endif
  192. #if !OGLPLUS_ERROR_INFO_NO_FUNC
  193. , const char* func
  194. #endif
  195. #if !OGLPLUS_ERROR_INFO_NO_LINE
  196. , const unsigned line
  197. #endif
  198. #if !OGLPLUS_ERROR_INFO_NO_CLASS_NAME
  199. , const char* cls_name
  200. #endif
  201. #if !OGLPLUS_ERROR_INFO_NO_BIND_TARGET
  202. , const StrLit& bind_tgt
  203. #endif
  204. #if !OGLPLUS_ERROR_INFO_NO_OBJECT_DESC
  205. , const String& (*get_obj_desc)(GLuint)
  206. , void (*purge_archive)(void)
  207. , GLuint obj_name
  208. #endif
  209. ): _dummy(dummy)
  210. #if !OGLPLUS_ERROR_INFO_NO_GL_SYMBOL
  211. , _glsym(glsym)
  212. #endif
  213. #if !OGLPLUS_ERROR_INFO_NO_FILE
  214. , _file(file)
  215. #endif
  216. #if !OGLPLUS_ERROR_INFO_NO_FUNC
  217. , _func(func)
  218. #endif
  219. #if !OGLPLUS_ERROR_INFO_NO_LINE
  220. , _line(line)
  221. #endif
  222. #if !OGLPLUS_ERROR_INFO_NO_CLASS_NAME
  223. , _cls_name(cls_name)
  224. #endif
  225. #if !OGLPLUS_ERROR_INFO_NO_BIND_TARGET
  226. , _bind_tgt(bind_tgt)
  227. #endif
  228. #if !OGLPLUS_ERROR_INFO_NO_OBJECT_DESC
  229. , _get_obj_desc(get_obj_desc)
  230. , _purge_archive(purge_archive)
  231. , _obj_name(obj_name)
  232. #endif
  233. { }
  234. };
  235. /// Returns the name of the symbol or constant related to the error
  236. /** This function returns the name of the failed OpenGL function
  237. * without the gl prefix in case of a function error or the name
  238. * of the OpenGL constant (usually a implementation-dependent) limit
  239. * which are related to the error.
  240. *
  241. * The result of this function is also influenced by the
  242. * #OGLPLUS_ERROR_INFO_NO_GL_SYMBOL preprocessor configuration option.
  243. * If set to zero this function behaves as described above, otherwise it
  244. * returns an empty C string.
  245. *
  246. * @see ErrorInfo
  247. * @see ErrorFunc()
  248. * @see ErrorFile()
  249. * @see ErrorLine()
  250. * @see ErrorClassName()
  251. * @see ErrorBindTarget()
  252. * @see ErrorObjectDescription()
  253. *
  254. * @ingroup error_handling
  255. */
  256. inline const char* ErrorGLSymbol(const ErrorInfo& info)
  257. {
  258. #if !OGLPLUS_ERROR_INFO_NO_GL_SYMBOL
  259. return info._glsym;
  260. #else
  261. return "";
  262. #endif
  263. }
  264. /// Returns the path of the source file where the exception originated
  265. /**
  266. * The result of this function is also influenced by the
  267. * #OGLPLUS_ERROR_INFO_NO_FILE preprocessor configuration option.
  268. * If set to zero this function behaves as described above, otherwise it
  269. * returns an empty C string.
  270. *
  271. * @see ErrorInfo
  272. * @see ErrorGLSymbol()
  273. * @see ErrorFunc()
  274. * @see ErrorLine()
  275. * @see ErrorClassName()
  276. * @see ErrorBindTarget()
  277. * @see ErrorObjectDescription()
  278. *
  279. * @ingroup error_handling
  280. */
  281. inline const char* ErrorFile(const ErrorInfo& info)
  282. {
  283. #if !OGLPLUS_ERROR_INFO_NO_FILE
  284. return info._file;
  285. #else
  286. OGLPLUS_FAKE_USE(info);
  287. return "";
  288. #endif
  289. }
  290. /// Returns the name of the function where the exception originated
  291. /**
  292. * The result of this function is also influenced by the
  293. * #OGLPLUS_ERROR_INFO_NO_FUNC preprocessor configuration option.
  294. * If set to zero this function behaves as described above, otherwise it
  295. * returns an empty C string.
  296. *
  297. * @see ErrorInfo
  298. * @see ErrorGLSymbol()
  299. * @see ErrorFile()
  300. * @see ErrorLine()
  301. * @see ErrorClassName()
  302. * @see ErrorBindTarget()
  303. * @see ErrorObjectDescription()
  304. *
  305. * @ingroup error_handling
  306. */
  307. inline const char* ErrorFunc(const ErrorInfo& info)
  308. {
  309. #if !OGLPLUS_ERROR_INFO_NO_FUNC
  310. return info._func;
  311. #else
  312. OGLPLUS_FAKE_USE(info);
  313. return "";
  314. #endif
  315. }
  316. /// Returns the line in the source file where the exception originated
  317. /**
  318. * The result of this function is also influenced by the
  319. * #OGLPLUS_ERROR_INFO_NO_LINE preprocessor configuration option.
  320. * If set to zero this function behaves as described above, otherwise it
  321. * returns zero.
  322. *
  323. * @see ErrorInfo
  324. * @see ErrorGLSymbol()
  325. * @see ErrorFile()
  326. * @see ErrorFunc()
  327. * @see ErrorClassName()
  328. * @see ErrorBindTarget()
  329. * @see ErrorObjectDescription()
  330. *
  331. * @ingroup error_handling
  332. */
  333. inline unsigned ErrorLine(const ErrorInfo& info)
  334. {
  335. #if !OGLPLUS_ERROR_INFO_NO_LINE
  336. return info._line;
  337. #else
  338. OGLPLUS_FAKE_USE(info);
  339. return 0;
  340. #endif
  341. }
  342. /// Returns the name of the class of the object where the exception originated
  343. /**
  344. * The result of this function is also influenced by the
  345. * #OGLPLUS_ERROR_INFO_NO_CLASS_NAME preprocessor configuration option.
  346. * If set to zero this function behaves as described above, otherwise it
  347. * returns the string "UnknownClass".
  348. *
  349. * @see ErrorInfo
  350. * @see ErrorGLSymbol()
  351. * @see ErrorFile()
  352. * @see ErrorFunc()
  353. * @see ErrorLine()
  354. * @see ErrorBindTarget()
  355. * @see ErrorObjectDescription()
  356. *
  357. * @ingroup error_handling
  358. */
  359. inline const char* ErrorClassName(const ErrorInfo& info)
  360. {
  361. #if !OGLPLUS_ERROR_INFO_NO_CLASS_NAME
  362. return (info._cls_name && *info._cls_name) ?
  363. info._cls_name :
  364. "UnknownClass";
  365. #else
  366. OGLPLUS_FAKE_USE(info);
  367. return "UnknownClass";
  368. #endif
  369. }
  370. /// Returns the name of the binding point the object where the exception originated
  371. /**
  372. * The result of this function is also influenced by the
  373. * #OGLPLUS_ERROR_INFO_NO_BIND_TARGET preprocessor configuration option.
  374. * If set to zero this function behaves as described above, otherwise it
  375. * returns the string "UnknownTarget".
  376. *
  377. * @see ErrorInfo
  378. * @see ErrorGLSymbol()
  379. * @see ErrorFile()
  380. * @see ErrorFunc()
  381. * @see ErrorLine()
  382. * @see ErrorClassName()
  383. * @see ErrorObjectDescription()
  384. *
  385. * @ingroup error_handling
  386. */
  387. inline const char* ErrorBindTarget(const ErrorInfo& info)
  388. {
  389. OGLPLUS_FAKE_USE(info);
  390. return
  391. #if !OGLPLUS_ERROR_INFO_NO_BIND_TARGET
  392. (info._bind_tgt) ?
  393. info._bind_tgt.c_str() :
  394. #endif
  395. "UnknownTarget";
  396. }
  397. /// Returns the optional description of the object related to the error
  398. /**
  399. * The result of this function is also influenced by the
  400. * #OGLPLUS_ERROR_INFO_NO_OBJECT_DESC preprocessor configuration option.
  401. * If set to zero this function behaves as described above, otherwise it
  402. * returns an empty string.
  403. *
  404. * @see ErrorInfo
  405. * @see ErrorGLSymbol()
  406. * @see ErrorFile()
  407. * @see ErrorFunc()
  408. * @see ErrorLine()
  409. * @see ErrorClassName()
  410. * @see ErrorBindTarget()
  411. *
  412. * @ingroup error_handling
  413. */
  414. inline const String& ErrorObjectDescription(const ErrorInfo& info)
  415. {
  416. OGLPLUS_FAKE_USE(info);
  417. #if !OGLPLUS_ERROR_INFO_NO_OBJECT_DESC
  418. if((info._get_obj_desc != 0) && (info._obj_name != 0))
  419. return info._get_obj_desc(info._obj_name);
  420. #endif
  421. return aux::EmptyString();
  422. }
  423. /// Exception class for general OpenGL errors
  424. /** Instances of this exception class are throws whenever an error is detected
  425. * during the execution of OpenGL API calls in the @OGLplus code. There are several
  426. * other classes derived for more specific error types, like GL shading language
  427. * compilation and linking errors, out-of-memory errors, etc.
  428. * This class is derived from the standard runtime_error exception and thus
  429. * the basic error message can be obtained by calling its @c what() member function.
  430. *
  431. * @ingroup error_handling
  432. */
  433. class Error
  434. : public std::runtime_error
  435. {
  436. public:
  437. /// A map of properties attached to the exception
  438. typedef std::map<String, String> PropertyMap;
  439. #if !OGLPLUS_ERROR_NO_PROPERTIES
  440. typedef PropertyMap PropertyMapInit;
  441. #else
  442. struct PropertyMapInit { };
  443. #endif
  444. /// List of ErrorInfo objects marking exception trace points
  445. typedef std::list<ErrorInfo> PropagationInfoList;
  446. private:
  447. GLenum _code;
  448. ErrorInfo _info;
  449. #if !OGLPLUS_ERROR_NO_PROPERTIES
  450. PropertyMap _properties;
  451. #endif
  452. #if !OGLPLUS_ERROR_NO_PROPAGATION_INFO
  453. PropagationInfoList _propagation;
  454. #endif
  455. bool _assertion;
  456. public:
  457. Error(
  458. GLenum code,
  459. const char* desc,
  460. const ErrorInfo& info,
  461. bool assertion = false
  462. ): std::runtime_error(desc)
  463. , _code(code)
  464. , _info(info)
  465. , _assertion(assertion)
  466. { }
  467. Error(
  468. GLenum code,
  469. const char* desc,
  470. const ErrorInfo& info,
  471. PropertyMapInit&& properties
  472. ): std::runtime_error(desc)
  473. , _code(code)
  474. , _info(info)
  475. #if !OGLPLUS_ERROR_NO_PROPERTIES
  476. , _properties(std::move(properties))
  477. #endif
  478. , _assertion(false)
  479. {
  480. #if OGLPLUS_ERROR_NO_PROPERTIES
  481. OGLPLUS_FAKE_USE(properties);
  482. #endif
  483. }
  484. inline ~Error(void) throw()
  485. { }
  486. /// Returns the OpenGL error code
  487. /** This is basically the value of error code returned by the glGetError
  488. * functions.
  489. *
  490. * @see ThrowInfo
  491. * @see File
  492. * @see Func
  493. * @see Line
  494. * @see ClassName
  495. * @see ObjectDescription
  496. */
  497. GLenum Code(void) const
  498. {
  499. return _code;
  500. }
  501. /// Returns information about the throw site of the exception
  502. /**
  503. * @see GLSymbol
  504. * @see Code
  505. * @see File
  506. * @see Func
  507. * @see Line
  508. * @see ClassName
  509. * @see ObjectDescription
  510. */
  511. const ErrorInfo& ThrowInfo(void) const
  512. {
  513. return _info;
  514. }
  515. /// Returns the name of the symbol or constant related to the error
  516. /** This function returns the name of the failed OpenGL function
  517. * without the gl prefix in case of a function error or the name
  518. * of the OpenGL constant (usually a implementation-dependent) limit
  519. * which are related to the error.
  520. *
  521. * @see ThrowInfo
  522. * @see Code
  523. * @see Func
  524. * @see File
  525. * @see Line
  526. * @see ClassName
  527. * @see ObjectDescription
  528. */
  529. const char* GLSymbol(void) const
  530. {
  531. return ::oglplus::ErrorGLSymbol(_info);
  532. }
  533. /// Returns the path of the source file where the exception originated
  534. /**
  535. * @see ThrowInfo
  536. * @see GLSymbol
  537. * @see Code
  538. * @see Func
  539. * @see Line
  540. * @see ClassName
  541. * @see ObjectDescription
  542. */
  543. const char* File(void) const
  544. {
  545. return ::oglplus::ErrorFile(_info);
  546. }
  547. /// Returns the name of the function where the exception originated
  548. /**
  549. * @see ThrowInfo
  550. * @see GLSymbol
  551. * @see Code
  552. * @see File
  553. * @see Line
  554. * @see ClassName
  555. * @see ObjectDescription
  556. */
  557. const char* Func(void) const
  558. {
  559. return ::oglplus::ErrorFunc(_info);
  560. }
  561. /// Returns the line in the source file where the exception originated
  562. /**
  563. * @see ThrowInfo
  564. * @see GLSymbol
  565. * @see Code
  566. * @see File
  567. * @see Func
  568. * @see ClassName
  569. * @see ObjectDescription
  570. */
  571. unsigned Line(void) const
  572. {
  573. return ::oglplus::ErrorLine(_info);
  574. }
  575. /// Returns the class name of the object that caused the exception
  576. const char* ClassName(void) const
  577. {
  578. return ::oglplus::ErrorClassName(_info);
  579. }
  580. /// Returns the name of the binding point that caused the exception
  581. const char* BindTarget(void) const
  582. {
  583. return ::oglplus::ErrorBindTarget(_info);
  584. }
  585. /// Returns the description of the object that caused the exception
  586. const String& ObjectDescription(void) const
  587. {
  588. return ::oglplus::ErrorObjectDescription(_info);
  589. }
  590. #if OGLPLUS_DOCUMENTATION_ONLY || OGLPLUS_ERROR_NO_PROPERTIES
  591. /// Returns the properties of the exception
  592. /**
  593. * @see #OGLPLUS_ERROR_NO_PROPERTIES
  594. */
  595. PropertyMap Properties(void) const
  596. {
  597. return PropertyMap();
  598. }
  599. #else
  600. const PropertyMap& Properties(void) const
  601. {
  602. return _properties;
  603. }
  604. #endif
  605. #if OGLPLUS_DOCUMENTATION_ONLY || !OGLPLUS_ERROR_NO_PROPERTIES
  606. /// Set a property key/value to the property map
  607. template <typename Key, typename Value>
  608. static void AddPropertyValue(
  609. PropertyMapInit& properties,
  610. Key&& key,
  611. Value&& value
  612. )
  613. {
  614. properties[key] = value;
  615. }
  616. #else
  617. template <typename Key, typename Value>
  618. static void AddPropertyValue(PropertyMapInit&, Key&&, Value&&) { }
  619. #endif
  620. /// Set a property key/value to the exception
  621. void SetPropertyValue(const String& key, const String& value)
  622. {
  623. #if !OGLPLUS_ERROR_NO_PROPERTIES
  624. _properties[key] = value;
  625. #else
  626. OGLPLUS_FAKE_USE(key);
  627. OGLPLUS_FAKE_USE(value);
  628. #endif
  629. }
  630. #if OGLPLUS_DOCUMENTATION_ONLY || OGLPLUS_ERROR_NO_PROPAGATION_INFO
  631. /// Returns a list of ErrorInfo objects marking exception trace points
  632. /**
  633. * @see #OGLPLUS_ERROR_NO_PROPAGATION_INFO
  634. */
  635. PropagationInfoList PropagationInfo(void) const
  636. {
  637. return PropagationInfoList();
  638. }
  639. #else
  640. const PropagationInfoList& PropagationInfo(void) const
  641. {
  642. return _propagation;
  643. }
  644. #endif
  645. void Trace(const ErrorInfo& info)
  646. {
  647. #if !OGLPLUS_ERROR_NO_PROPAGATION_INFO
  648. _propagation.push_back(info);
  649. #else
  650. OGLPLUS_FAKE_USE(info);
  651. #endif
  652. throw;
  653. }
  654. void Cleanup(void) const
  655. {
  656. #if !OGLPLUS_ERROR_INFO_NO_OBJECT_DESC
  657. if(_info._purge_archive != 0)
  658. _info._purge_archive();
  659. for(auto i=_propagation.begin(),e=_propagation.end();i!=e;++i)
  660. {
  661. if(i->_purge_archive != 0)
  662. i->_purge_archive();
  663. }
  664. #endif
  665. }
  666. };
  667. /// Exception class for out-of-memory OpenGL errors
  668. /** Out-of-memory is a very serious error and applications generally should not
  669. * try to recover from such errors, but terminate gracefully if possible.
  670. *
  671. * @ingroup error_handling
  672. */
  673. class OutOfMemory
  674. : public Error
  675. {
  676. public:
  677. OutOfMemory(GLenum code, const char* desc, const ErrorInfo& info)
  678. : Error(code, desc, info, true)
  679. { }
  680. };
  681. #if OGLPLUS_DOCUMENTATION_ONLY
  682. /// Exception class for situations when a pointer to a GL function is invalid.
  683. /** @OGLplus optionally (based on the value of the #OGLPLUS_NO_GLFUNC_CHECKS
  684. * compile-time switch) checks, if pointers to OpenGL functions are valid
  685. * (i.e. not @c nullptr). OpenGL functions are usually called through pointers,
  686. * when using a library such as GLEW, which tries to find and get the addresses
  687. * of GL functions from the GL library dynamically at run-time. Sometimes
  688. * the pointers to several of the functions remain uninitialized and usually
  689. * result in a memory violation and program termination if called.
  690. *
  691. * The MissingFunction exception class indicates that the usage
  692. * of such uninitialized function pointer was detected at run-time
  693. * and allows the application to terminate more gracefully.
  694. *
  695. * @see #OGLPLUS_NO_GLFUNC_CHECKS
  696. *
  697. * @ingroup error_handling
  698. */
  699. class MissingFunction
  700. : public Error
  701. { };
  702. #else
  703. class MissingFunction
  704. : public Error
  705. {
  706. public:
  707. MissingFunction(GLenum code, const char* msg, const ErrorInfo& info)
  708. : Error(code, msg, info, true)
  709. { }
  710. };
  711. #endif
  712. /// Exception indicating exceeded implementation-defined limits
  713. /** Instances of this class are thrown if an instance of a (usually unsigned
  714. * integer) type is assigned a value that it is outside of an implementation
  715. * dependent range. This includes things like limits on the number of texture
  716. * units of the GPU, the maximum texture dimensions, maximum number of draw
  717. * buffers, vertex attributes, etc.
  718. *
  719. * @ingroup error_handling
  720. */
  721. class LimitError
  722. : public Error
  723. {
  724. private:
  725. GLuint _value;
  726. GLuint _limit;
  727. public:
  728. LimitError(
  729. GLuint value,
  730. GLuint limit,
  731. const GLchar* msg,
  732. const ErrorInfo& info
  733. ): Error(GL_INVALID_VALUE, msg, info)
  734. , _value(value)
  735. , _limit(limit)
  736. { }
  737. /// The value assigned to the limited-type variable
  738. GLuint Value(void) const
  739. {
  740. return _value;
  741. }
  742. /// The allowed limit of the limited-type
  743. GLuint Limit(void) const
  744. {
  745. return _limit;
  746. }
  747. };
  748. /// Exception indicating shader variable-related error
  749. /** Instances of this class are thrown when an invalid shader variable-related
  750. * operation is performed, for example when a value of a invalid type is
  751. * assigned to a shader uniform variable or vertex attribute.
  752. *
  753. * @ingroup error_handling
  754. */
  755. class ShaderVariableError
  756. : public Error
  757. {
  758. private:
  759. GLint _location;
  760. public:
  761. ShaderVariableError(
  762. GLenum code,
  763. GLint location,
  764. const GLchar* msg,
  765. const ErrorInfo& info,
  766. Error::PropertyMapInit&& properties
  767. ): Error(code, msg, info, std::move(properties))
  768. , _location(location)
  769. { }
  770. /// The location of the shader variable (uniform, vertex attribute)
  771. /** This is the value either assigned by the GL or explicitly specified
  772. * by the GLSL layout location specifier or bound by BindAttribLocation
  773. */
  774. GLint Location(void) const
  775. {
  776. return _location;
  777. }
  778. };
  779. #if OGLPLUS_DOCUMENTATION_ONLY || OGLPLUS_CUSTOM_ERROR_HANDLING
  780. /// Structure containing all error-related data; Used in custom error handlers
  781. /**
  782. * Available only if the #OGLPLUS_CUSTOM_ERROR_HANDLING compile-time switch
  783. * is set to a nonzero value.
  784. *
  785. * @ingroup error_handling
  786. */
  787. struct ErrorData
  788. {
  789. private:
  790. GLenum _error_code;
  791. GLuint _value;
  792. GLuint _limit;
  793. const char* _message;
  794. ErrorInfo _info;
  795. Error::PropertyMap _properties;
  796. bool _assertion;
  797. bool _fatal_error;
  798. bool _build_error;
  799. bool _limit_error;
  800. public:
  801. /// The OpenGL error code
  802. inline GLenum ErrorCode(void) const
  803. {
  804. return _error_code;
  805. }
  806. /// The invalid value that caused a limit error
  807. inline GLuint Value(void) const
  808. {
  809. return _value;
  810. }
  811. /// The limited value limit
  812. inline GLuint Limit(void) const
  813. {
  814. return _limit;
  815. }
  816. /// The error message
  817. /** The returned pointer should not be used when its ErrorData instance
  818. * goes out of scope. If this is necessary the string should be copied.
  819. */
  820. inline const char* Message(void) const
  821. {
  822. return _message;
  823. }
  824. /// Additional error info
  825. inline const ErrorInfo& Info(void) const
  826. {
  827. return _info;
  828. }
  829. /// Additional error property (key/values)
  830. inline const Error::PropertyMap& Properties(void) const
  831. {
  832. return _properties;
  833. }
  834. /// Indicates that an assertion has failed
  835. inline bool Assertion(void) const
  836. {
  837. return _assertion;
  838. }
  839. /// Indicates a fatal (very severe) error like (out of memory)
  840. inline bool FatalError(void) const
  841. {
  842. return _fatal_error;
  843. }
  844. /// Indicates a build error
  845. inline bool BuildError(void) const
  846. {
  847. return _build_error;
  848. }
  849. /// Indicates a limited value error
  850. inline bool LimitError(void) const
  851. {
  852. return _limit_error;
  853. }
  854. inline ErrorData(
  855. GLenum error_code,
  856. GLuint value,
  857. GLuint limit,
  858. const char* message,
  859. const ErrorInfo& info,
  860. Error::PropertyMapInit&& properties,
  861. bool assertion,
  862. bool fatal_error,
  863. bool build_error,
  864. bool limit_error
  865. ): _error_code(error_code)
  866. , _value(value)
  867. , _limit(limit)
  868. , _message(message)
  869. , _info(info)
  870. , _properties(std::move(properties))
  871. , _assertion(assertion)
  872. , _fatal_error(fatal_error)
  873. , _build_error(build_error)
  874. , _limit_error(limit_error)
  875. { }
  876. };
  877. /// Type of installable custom error handler functor
  878. /**
  879. * Available only if the #OGLPLUS_CUSTOM_ERROR_HANDLING compile-time switch
  880. * is set to a nonzero value.
  881. *
  882. * @ingroup error_handling
  883. */
  884. typedef std::function<bool (const ErrorData&)> ErrorHandlerFunc;
  885. namespace aux {
  886. inline std::stack<ErrorHandlerFunc>& _error_handlers(void)
  887. {
  888. static std::stack<ErrorHandlerFunc> _handlers;
  889. return _handlers;
  890. }
  891. inline bool _has_error_handler(void)
  892. {
  893. return !_error_handlers().empty();
  894. }
  895. inline ErrorHandlerFunc& _get_error_handler(void)
  896. {
  897. assert(!_error_handlers().empty());
  898. return _error_handlers().top();
  899. }
  900. } // namespace aux
  901. /// A RAII class installing a temporary custom error handler
  902. /**
  903. * Available only if the #OGLPLUS_CUSTOM_ERROR_HANDLING compile-time switch
  904. * is set to a nonzero value.
  905. *
  906. * @ingroup error_handling
  907. */
  908. class LocalErrorHandler
  909. {
  910. private:
  911. size_t _installed;
  912. public:
  913. /// Installs the specified error @p handler
  914. LocalErrorHandler(ErrorHandlerFunc handler)
  915. {
  916. aux::_error_handlers().push(handler);
  917. _installed = aux::_error_handlers().size();
  918. }
  919. /// This class is non-copyable
  920. LocalErrorHandler(const LocalErrorHandler&) = delete;
  921. /// Uninstalls the previously installed handler
  922. ~LocalErrorHandler(void)
  923. {
  924. if(_installed)
  925. {
  926. assert(aux::_error_handlers().size() == _installed);
  927. aux::_error_handlers().pop();
  928. }
  929. }
  930. };
  931. #endif // OGLPLUS_CUSTOM_ERROR_HANDLING
  932. template <class Exception>
  933. inline void HandleBuildError(const String& msg, const ErrorInfo& info)
  934. {
  935. #if OGLPLUS_CUSTOM_ERROR_HANDLING
  936. if(aux::_has_error_handler() && aux::_get_error_handler()(
  937. ErrorData(
  938. GL_INVALID_OPERATION,
  939. 0u, 0u,
  940. msg.c_str(),
  941. info,
  942. Error::PropertyMapInit(),
  943. false,
  944. false,
  945. true,
  946. false
  947. )
  948. )) return;
  949. #endif // OGLPLUS_CUSTOM_ERROR_HANDLING
  950. throw Exception(msg, info);
  951. }
  952. inline void HandleShaderVariableError(
  953. GLenum code,
  954. GLint location,
  955. const GLchar* msg,
  956. const ErrorInfo& info,
  957. Error::PropertyMapInit&& properties
  958. )
  959. {
  960. #if OGLPLUS_CUSTOM_ERROR_HANDLING
  961. if(aux::_has_error_handler() && aux::_get_error_handler()(
  962. ErrorData(
  963. code,
  964. 0u, 0u,
  965. msg,
  966. info,
  967. Error::PropertyMapInit(),
  968. false,
  969. false,
  970. false,
  971. false
  972. )
  973. )) return;
  974. #endif // OGLPLUS_CUSTOM_ERROR_HANDLING
  975. throw ShaderVariableError(
  976. code,
  977. location,
  978. msg,
  979. info,
  980. std::move(properties)
  981. );
  982. }
  983. inline void HandleLimitError(GLuint value, GLuint limit, const ErrorInfo& info)
  984. {
  985. const GLchar* msg = "OpenGL limited value out of range";
  986. #if OGLPLUS_CUSTOM_ERROR_HANDLING
  987. if(aux::_has_error_handler() && aux::_get_error_handler()(
  988. ErrorData(
  989. GL_INVALID_VALUE,
  990. value, limit,
  991. msg,
  992. info,
  993. Error::PropertyMapInit(),
  994. false,
  995. false,
  996. false,
  997. true
  998. )
  999. )) return;
  1000. #endif // OGLPLUS_CUSTOM_ERROR_HANDLING
  1001. throw LimitError(value, limit, msg, info);
  1002. }
  1003. template <class Exception, typename FBStatus>
  1004. inline void HandleIncompleteFramebuffer(
  1005. FBStatus status,
  1006. const ErrorInfo& info
  1007. )
  1008. {
  1009. const GLchar* msg = "Framebuffer is incomplete";
  1010. #if OGLPLUS_CUSTOM_ERROR_HANDLING
  1011. if(aux::_has_error_handler() && aux::_get_error_handler()(
  1012. ErrorData(
  1013. GL_INVALID_FRAMEBUFFER_OPERATION,
  1014. 0u, 0u,
  1015. msg,
  1016. info,
  1017. Error::PropertyMapInit(),
  1018. false,
  1019. false,
  1020. false,
  1021. true
  1022. )
  1023. )) return;
  1024. #endif // OGLPLUS_CUSTOM_ERROR_HANDLING
  1025. throw Exception(status, msg, info);
  1026. }
  1027. #if !OGLPLUS_NO_VARIADIC_TEMPLATES && !OGLPLUS_NO_GLFUNC_CHECKS
  1028. inline void HandleMissingFunction(const ErrorInfo& info)
  1029. {
  1030. const GLenum code = GL_INVALID_VALUE;
  1031. const char* msg = "Function called through an invalid pointer";
  1032. #if OGLPLUS_CUSTOM_ERROR_HANDLING
  1033. if(aux::_has_error_handler() && aux::_get_error_handler()(
  1034. ErrorData(
  1035. code,
  1036. 0u, 0u,
  1037. msg,
  1038. info,
  1039. Error::PropertyMapInit(),
  1040. true,
  1041. true,
  1042. false,
  1043. false
  1044. )
  1045. )) return;
  1046. #endif // OGLPLUS_CUSTOM_ERROR_HANDLING
  1047. throw MissingFunction(code, msg, info);
  1048. }
  1049. #endif // OGLPLUS_NO_VARIADIC_TEMPLATES || OGLPLUS_NO_GLFUNC_CHECKS
  1050. inline void HandleError(
  1051. GLenum code,
  1052. const GLchar* msg,
  1053. const ErrorInfo& info,
  1054. Error::PropertyMapInit&& properties
  1055. )
  1056. {
  1057. #if OGLPLUS_CUSTOM_ERROR_HANDLING
  1058. if(aux::_has_error_handler() && aux::_get_error_handler()(
  1059. ErrorData(
  1060. code,
  1061. 0, 0,
  1062. msg,
  1063. info,
  1064. std::move(properties),
  1065. false,
  1066. code == GL_OUT_OF_MEMORY,
  1067. false,
  1068. false
  1069. )
  1070. )) return;
  1071. #endif // OGLPLUS_CUSTOM_ERROR_HANDLING
  1072. throw Error(
  1073. code,
  1074. msg,
  1075. info,
  1076. std::move(properties)
  1077. );
  1078. }
  1079. inline void HandleError(GLenum code, const ErrorInfo& info, bool assertion)
  1080. {
  1081. const GLchar* msg = "Unknown error";
  1082. switch(code)
  1083. {
  1084. case GL_OUT_OF_MEMORY:
  1085. msg = "OpenGL out of memory";
  1086. break;
  1087. case GL_INVALID_ENUM:
  1088. msg = "Invalid OpenGL enum argument";
  1089. break;
  1090. case GL_INVALID_VALUE:
  1091. msg = "OpenGL numeric argument out of range";
  1092. break;
  1093. case GL_INVALID_OPERATION:
  1094. msg = "Invalid OpenGL operation";
  1095. break;
  1096. case GL_INVALID_FRAMEBUFFER_OPERATION:
  1097. msg = "Invalid OpenGL framebuffer operation";
  1098. break;
  1099. #ifdef GL_STACK_OVERFLOW
  1100. case GL_STACK_OVERFLOW:
  1101. msg = "Stack overflow";
  1102. break;
  1103. #endif
  1104. #ifdef GL_STACK_UNDERFLOW
  1105. case GL_STACK_UNDERFLOW:
  1106. msg = "Stack underflow";
  1107. break;
  1108. #endif
  1109. #ifdef GL_TABLE_TOO_LARGE
  1110. case GL_TABLE_TOO_LARGE:
  1111. msg = "Table too large";
  1112. break;
  1113. #endif
  1114. }
  1115. #if OGLPLUS_CUSTOM_ERROR_HANDLING
  1116. if(aux::_has_error_handler() && aux::_get_error_handler()(
  1117. ErrorData(
  1118. code,
  1119. 0, 0,
  1120. msg,
  1121. info,
  1122. Error::PropertyMapInit(),
  1123. assertion,
  1124. code == GL_OUT_OF_MEMORY,
  1125. false,
  1126. false
  1127. )
  1128. )) return;
  1129. #endif // OGLPLUS_CUSTOM_ERROR_HANDLING
  1130. throw Error(code, msg, info, assertion);
  1131. }
  1132. #if OGLPLUS_DOCUMENTATION_ONLY
  1133. /// This macro decides if error handling should be done
  1134. /** The @p EXPRESSION parameter is a boolean expression
  1135. * and true values indicate an error condition. If this
  1136. * macro returns a false expression any error handling
  1137. * is skipped.
  1138. */
  1139. #define OGLPLUS_IS_ERROR(EXPRESSION)
  1140. #endif
  1141. #ifndef OGLPLUS_IS_ERROR
  1142. #define OGLPLUS_IS_ERROR(EXPRESSION) (EXPRESSION)
  1143. #endif
  1144. #if OGLPLUS_DOCUMENTATION_ONLY
  1145. /// Macro checking and possibly handling run-time errors in previous call to GL
  1146. /** This macro is called immediatelly after calls to GL functions
  1147. * that may fail due to invalid values of run-time parameters.
  1148. */
  1149. #define OGLPLUS_CHECK(PARAM)
  1150. #endif
  1151. #ifndef OGLPLUS_CHECK
  1152. #define OGLPLUS_CHECK(PARAM) { \
  1153. GLenum error_code = ::glGetError(); \
  1154. if(error_code != GL_NO_ERROR) HandleError(error_code, PARAM, false); \
  1155. }
  1156. #endif
  1157. #if OGLPLUS_DOCUMENTATION_ONLY
  1158. /// Macro asserting that no errors occured in prevous call to GL
  1159. /** This macro is called immediatelly after calls to GL functions
  1160. * that "should not" fail and if they do fail it indicates
  1161. * a program logic error that is not dependent on run-time parameters.
  1162. */
  1163. #define OGLPLUS_VERIFY(PARAM)
  1164. #endif
  1165. #ifndef OGLPLUS_VERIFY
  1166. #if !OGPLUS_LOW_PROFILE
  1167. #define OGLPLUS_VERIFY(PARAM) { \
  1168. GLenum error_code = ::glGetError(); \
  1169. if(error_code != GL_NO_ERROR) HandleError(error_code, PARAM, true); \
  1170. }
  1171. #else
  1172. #define OGLPLUS_VERIFY(PARAM)
  1173. #endif
  1174. #endif
  1175. #define OGLPLUS_IGNORE(PARAM) ::glGetError();
  1176. } // namespace oglplus
  1177. #endif // include guard