1/*=========================================================================
2
3  Program:   Visualization Toolkit
4  Module:    vtkOpenGLError.h
5
6  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7  All rights reserved.
8  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9
10     This software is distributed WITHOUT ANY WARRANTY; without even
11     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12     PURPOSE.  See the above copyright notice for more information.
13
14=========================================================================*/
15#ifndef vtkOpenGLError_h
16#define vtkOpenGLError_h
17
18#include "vtkSetGet.h"
19#include "vtk_glew.h"
20#include <sstream>
21
22#ifndef NDEBUG
23// debug build.
24#cmakedefine VTK_REPORT_OPENGL_ERRORS
25#else // NDEBUG
26// release build
27#cmakedefine VTK_REPORT_OPENGL_ERRORS_IN_RELEASE_BUILDS
28#if defined(VTK_REPORT_OPENGL_ERRORS_IN_RELEASE_BUILDS)
29#cmakedefine VTK_REPORT_OPENGL_ERRORS
30#endif // defined(VTK_REPORT_OPENGL_ERRORS_IN_RELEASE_BUILDS)
31#endif // NDEBUG
32
33/**
34 * The following functions can be used to detect and report, and/or
35 * silently clear OpenGL error flags. These are not intended to be
36 * used directly, instead use the following macros.
37 *
38 * vtkOpenGLClearErrorMacro() -- Silently clear OpenGL error flags.
39 *
40 * vtkOpenGLCheckErrorMacro(message) -- Check and clear OpenGL's error
41 * flags. Report errors detected via vtkErrorMacro.
42 *
43 * vtkOpenGLStaticCheckErrorMacro(message) -- Check and clear OpenGL's
44 * error flags. Report errors detected via vtkGenericWarningMacro.
45 * This may be used in static methods and outside of vtkObjects.
46 *
47 * The intended usage pattern is to 1) call vtkOpenGLClearErrorMacro
48 * at the top of, and 2) vtkOpenGLCheckErrorMacro at the bottom of
49 * methods that make OpenGL calls.
50 *
51 * By calling vtkOpenGLClearErrorMacro at the top of a method that
52 * makes OpenGL calls, you isolate the code and prevent it from
53 * detecting any preceding errors. By calling vtkOpenGLCheckErrorMacro
54 * at the bottom of the method you clear the error flags and report
55 * any errors that have occurred in the method where they occurred.
56 *
57 * The macros maybe completely disabled via the CMakeLists variable
58 * VTK_REPORT_OPENGL_ERRORS. Note that in that case error flags are
59 * never cleared so that if an error occurs the flags will remain dirty
60 * making it impossible for anyone else to use them reliably. Please
61 * don't disable them with out a good reason.
62 */
63
64/**
65 * Convert an OpenGL error code into a descriptive
66 * string.
67 */
68inline
69const char *vtkOpenGLStrError(unsigned int code)
70{
71  switch(static_cast<GLenum>(code))
72  {
73    case GL_NO_ERROR:
74      return "No error";
75    case GL_INVALID_ENUM:
76      return "Invalid enum";
77    case GL_INVALID_VALUE:
78      return "Invalid value";
79    case GL_INVALID_OPERATION:
80      return "Invalid operation";
81    case GL_OUT_OF_MEMORY:
82      return "Out of memory";
83#if GL_ES_VERSION_3_0 != 1
84    case GL_STACK_OVERFLOW:
85      return "Stack overflow";
86    case GL_STACK_UNDERFLOW:
87      return "Stack underflow";
88    case GL_TABLE_TOO_LARGE:
89      return "Table too large";
90    case GL_INVALID_FRAMEBUFFER_OPERATION_EXT:
91      return "Invalid framebuffer operation";
92#endif
93  }
94  return "Unknown error";
95}
96
97/**
98 * Check for OpenGL errors. Error status is querried until
99 * OpenGL reports no errors. The list of errors and their
100 * descriptions are returned in the user supplied arrays.
101 * User passes the size of the arrays as the first argument.
102 * Error flags will still be cleared if the user arrays are
103 * less than the number of errors.
104 */
105#if defined(VTK_REPORT_OPENGL_ERRORS)
106inline
107int vtkGetOpenGLErrors(
108      int maxNum,
109      unsigned int *errCode,
110      const char **errDesc)
111{
112  int i = 0;
113  GLenum code = glGetError();
114  if (i < maxNum)
115  {
116    errCode[i] = static_cast<unsigned int>(code);
117    errDesc[i] = vtkOpenGLStrError(code);
118  }
119  while (code != GL_NO_ERROR && i < maxNum)
120  {
121    i++;
122    code = glGetError();
123    if (i < maxNum)
124    {
125      errCode[i] = static_cast<unsigned int>(code);
126      errDesc[i] = vtkOpenGLStrError(code);
127    }
128  }
129  return i;
130}
131#else
132inline
133int vtkGetOpenGLErrors(
134      int maxNum,
135      unsigned int *errCode,
136      const char **errDesc)
137{
138  (void)maxNum;
139  (void)errCode;
140  (void)errDesc;
141  return 0;
142}
143#endif
144
145/**
146 * Send a set of errors collected by GetOpenGLErrors
147 * to the give stream. The number of errors is obtained
148 * in the return value of GetOpenGLErrors, while the max
149 * errors gives the size of the error arrays.
150 */
151#if defined(VTK_REPORT_OPENGL_ERRORS)
152inline
153void vtkPrintOpenGLErrors(
154      ostream &os,
155      int maxErrors,
156      int numErrors,
157      unsigned int *errCode,
158      const char **errDesc)
159{
160  os << numErrors << " OpenGL errors detected" << endl;
161  for (int i=0; (i<numErrors)&&(i<maxErrors); ++i)
162  {
163    os << "  " <<  i << " : (" << errCode[i] << ") " << errDesc[i] << endl;
164  }
165  if (numErrors>maxErrors)
166  {
167    os
168      << "More than " << maxErrors
169      << " detected! The remainder are not reported"
170      << endl;
171  }
172}
173#else
174inline
175void vtkPrintOpenGLErrors(
176      ostream &os,
177      int maxErrors,
178      int numErrors,
179      unsigned int *errCode,
180      const char **errDesc)
181{
182  (void)os;
183  (void)maxErrors;
184  (void)numErrors;
185  (void)errCode;
186  (void)errDesc;
187}
188#endif
189
190/**
191 * Errors are queried and reported via vtkGenericWarningMacro. An optional
192 * header message can be appended to the stream. Returns true if no errors
193 * were reported.
194 */
195#if defined(VTK_REPORT_OPENGL_ERRORS)
196inline
197bool vtkOpenGLCheckErrors(const char* headerMessage = "")
198{
199  const int maxNumErrors = 16;
200  unsigned int errCode[maxNumErrors] = {0};
201  const char* errDesc[maxNumErrors] = {NULL};
202  int numErrors = vtkGetOpenGLErrors(maxNumErrors, errCode, errDesc);
203  if (numErrors > 0)
204  {
205    std::ostringstream oss;
206    vtkPrintOpenGLErrors(oss, maxNumErrors, numErrors, errCode, errDesc);
207    vtkGenericWarningMacro(<< headerMessage << oss.str().c_str());
208    return false;
209  }
210  return true;
211}
212#else
213inline
214bool vtkOpenGLCheckErrors(const char* errorMessage = "")
215{
216  (void)errorMessage;
217  return true;
218}
219#endif
220
221/**
222 * Clear OpenGL's error flags.
223 */
224#if defined(VTK_REPORT_OPENGL_ERRORS)
225inline
226void vtkClearOpenGLErrors(const unsigned int maxErrors = 16)
227{
228  GLenum glError;
229  unsigned int i = 0;
230  do
231  {
232    glError = glGetError();
233    ++i;
234  }
235  while(i < maxErrors && glError != GL_NO_ERROR);
236}
237#else
238inline
239void vtkClearOpenGLErrors(const unsigned int maxErrors = 16)
240{
241  (void) maxErrors;
242}
243#endif
244
245#if !defined(VTK_REPORT_OPENGL_ERRORS)
246# define vtkOpenGLClearErrorMacro()
247# define vtkOpenGLCheckErrorMacro(message)
248# define vtkOpenGLStaticCheckErrorMacro(message)
249#else
250# define vtkOpenGLClearErrorMacro() vtkClearOpenGLErrors(16);
251# include <sstream> // for error macro
252# define vtkOpenGLCheckErrorMacroImpl(ostr, message) \
253{                                                    \
254  const int maxErrors = 16;                          \
255  unsigned int errCode[maxErrors] = {0};             \
256  const char *errDesc[maxErrors] = {NULL};           \
257                                                     \
258  int numErrors                                      \
259    = vtkGetOpenGLErrors(                            \
260        maxErrors,                                   \
261        errCode,                                     \
262        errDesc);                                    \
263                                                     \
264  if (numErrors)                                     \
265  {                                                \
266    std::ostringstream oss;                          \
267    vtkPrintOpenGLErrors(                            \
268          oss,                                       \
269          maxErrors,                                 \
270          numErrors,                                 \
271          errCode,                                   \
272          errDesc);                                  \
273                                                     \
274    ostr(<< message << " " << oss.str().c_str());    \
275  }                                                \
276}
277# define vtkOpenGLCheckErrorMacro(message) \
278  vtkOpenGLCheckErrorMacroImpl(vtkErrorMacro, message)
279# define vtkOpenGLStaticCheckErrorMacro(message) \
280  vtkOpenGLCheckErrorMacroImpl(vtkGenericWarningMacro, message)
281#endif
282
283// Use this macro for fine grained error checking during
284// debugging. It is removed for Release builds.
285#ifdef NDEBUG
286# define vtkOpenGLDebugClearErrorMacro()
287# define vtkOpenGLDebugCheckErrorMacro(message)
288#else
289# define vtkOpenGLDebugClearErrorMacro() \
290  vtkOpenGLClearErrorMacro()
291# define vtkOpenGLDebugCheckErrorMacro(message) \
292  vtkOpenGLStaticCheckErrorMacro(message)
293#endif
294
295#endif
296// VTK-HeaderTest-Exclude: vtkOpenGLError.h
297