1 //
2 // Copyright (c) 2014 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 
6 // Error.h: Defines the egl::Error and gl::Error classes which encapsulate API errors
7 // and optional error messages.
8 
9 #ifndef LIBANGLE_ERROR_H_
10 #define LIBANGLE_ERROR_H_
11 
12 #include <EGL/egl.h>
13 #include <EGL/eglext.h>
14 #include "angle_gl.h"
15 #include "common/angleutils.h"
16 #include "common/debug.h"
17 
18 #include <memory>
19 #include <ostream>
20 #include <string>
21 
22 namespace angle
23 {
24 template <typename ErrorT, typename ResultT, typename ErrorBaseT, ErrorBaseT NoErrorVal>
25 class ANGLE_NO_DISCARD ErrorOrResultBase
26 {
27   public:
ErrorOrResultBase(const ErrorT & error)28     ErrorOrResultBase(const ErrorT &error) : mError(error) {}
ErrorOrResultBase(ErrorT && error)29     ErrorOrResultBase(ErrorT &&error) : mError(std::move(error)) {}
30 
ErrorOrResultBase(ResultT && result)31     ErrorOrResultBase(ResultT &&result) : mError(NoErrorVal), mResult(std::forward<ResultT>(result))
32     {
33     }
34 
ErrorOrResultBase(const ResultT & result)35     ErrorOrResultBase(const ResultT &result) : mError(NoErrorVal), mResult(result) {}
36 
isError()37     bool isError() const { return mError.isError(); }
getError()38     const ErrorT &getError() const { return mError; }
getResult()39     ResultT &&getResult() { return std::move(mResult); }
40 
41   private:
42     ErrorT mError;
43     ResultT mResult;
44 };
45 
46 template <typename ErrorT, typename ErrorBaseT, ErrorBaseT NoErrorVal, typename CodeT, CodeT EnumT>
47 class ErrorStreamBase : angle::NonCopyable
48 {
49   public:
ErrorStreamBase()50     ErrorStreamBase() : mID(EnumT) {}
ErrorStreamBase(GLuint id)51     ErrorStreamBase(GLuint id) : mID(id) {}
52 
53     template <typename T>
54     ErrorStreamBase &operator<<(T value)
55     {
56         mErrorStream << value;
57         return *this;
58     }
59 
ErrorT()60     operator ErrorT() { return ErrorT(EnumT, mID, mErrorStream.str()); }
61 
62     template <typename ResultT>
63     operator ErrorOrResultBase<ErrorT, ResultT, ErrorBaseT, NoErrorVal>()
64     {
65         return static_cast<ErrorT>(*this);
66     }
67 
68   private:
69     GLuint mID;
70     std::ostringstream mErrorStream;
71 };
72 }  // namespace angle
73 
74 namespace egl
75 {
76 class Error;
77 }  // namespace egl
78 
79 namespace gl
80 {
81 
82 class ANGLE_NO_DISCARD Error final
83 {
84   public:
85     explicit inline Error(GLenum errorCode);
86     Error(GLenum errorCode, std::string &&message);
87     Error(GLenum errorCode, GLuint id, std::string &&message);
88     inline Error(const Error &other);
89     inline Error(Error &&other);
90     inline ~Error() = default;
91 
92     // automatic error type conversion
93     inline Error(egl::Error &&eglErr);
94     inline Error(egl::Error eglErr);
95 
96     inline Error &operator=(const Error &other);
97     inline Error &operator=(Error &&other);
98 
99     inline GLenum getCode() const;
100     inline GLuint getID() const;
101     inline bool isError() const;
102 
103     const std::string &getMessage() const;
104 
105     // Useful for mocking and testing
106     bool operator==(const Error &other) const;
107     bool operator!=(const Error &other) const;
108 
109   private:
110     void createMessageString() const;
111 
112     friend std::ostream &operator<<(std::ostream &os, const Error &err);
113     friend class egl::Error;
114 
115     GLenum mCode;
116     GLuint mID;
117     mutable std::unique_ptr<std::string> mMessage;
118 };
119 
120 template <typename ResultT>
121 using ErrorOrResult = angle::ErrorOrResultBase<Error, ResultT, GLenum, GL_NO_ERROR>;
122 
123 namespace priv
124 {
125 
126 template <GLenum EnumT>
127 using ErrorStream = angle::ErrorStreamBase<Error, GLenum, GL_NO_ERROR, GLenum, EnumT>;
128 
129 }  // namespace priv
130 
131 using InternalError = priv::ErrorStream<GL_INVALID_OPERATION>;
132 
133 using InvalidEnum                 = priv::ErrorStream<GL_INVALID_ENUM>;
134 using InvalidValue                = priv::ErrorStream<GL_INVALID_VALUE>;
135 using InvalidOperation            = priv::ErrorStream<GL_INVALID_OPERATION>;
136 using StackOverflow               = priv::ErrorStream<GL_STACK_OVERFLOW>;
137 using StackUnderflow              = priv::ErrorStream<GL_STACK_UNDERFLOW>;
138 using OutOfMemory                 = priv::ErrorStream<GL_OUT_OF_MEMORY>;
139 using InvalidFramebufferOperation = priv::ErrorStream<GL_INVALID_FRAMEBUFFER_OPERATION>;
140 
NoError()141 inline Error NoError()
142 {
143     return Error(GL_NO_ERROR);
144 }
145 
146 using LinkResult = ErrorOrResult<bool>;
147 
148 }  // namespace gl
149 
150 namespace egl
151 {
152 
153 class ANGLE_NO_DISCARD Error final
154 {
155   public:
156     explicit inline Error(EGLint errorCode);
157     Error(EGLint errorCode, std::string &&message);
158     Error(EGLint errorCode, EGLint id, std::string &&message);
159     inline Error(const Error &other);
160     inline Error(Error &&other);
161     inline ~Error() = default;
162 
163     // automatic error type conversion
164     inline Error(gl::Error &&glErr);
165     inline Error(gl::Error glErr);
166 
167     inline Error &operator=(const Error &other);
168     inline Error &operator=(Error &&other);
169 
170     inline EGLint getCode() const;
171     inline EGLint getID() const;
172     inline bool isError() const;
173 
174     const std::string &getMessage() const;
175 
176   private:
177     void createMessageString() const;
178 
179     friend std::ostream &operator<<(std::ostream &os, const Error &err);
180     friend class gl::Error;
181 
182     EGLint mCode;
183     EGLint mID;
184     mutable std::unique_ptr<std::string> mMessage;
185 };
186 
187 template <typename ResultT>
188 using ErrorOrResult = angle::ErrorOrResultBase<Error, ResultT, EGLint, EGL_SUCCESS>;
189 
190 namespace priv
191 {
192 
193 template <EGLint EnumT>
194 using ErrorStream = angle::ErrorStreamBase<Error, EGLint, EGL_SUCCESS, EGLint, EnumT>;
195 
196 }  // namespace priv
197 
198 using EglNotInitialized    = priv::ErrorStream<EGL_NOT_INITIALIZED>;
199 using EglBadAccess         = priv::ErrorStream<EGL_BAD_ACCESS>;
200 using EglBadAlloc          = priv::ErrorStream<EGL_BAD_ALLOC>;
201 using EglBadAttribute      = priv::ErrorStream<EGL_BAD_ATTRIBUTE>;
202 using EglBadConfig         = priv::ErrorStream<EGL_BAD_CONFIG>;
203 using EglBadContext        = priv::ErrorStream<EGL_BAD_CONTEXT>;
204 using EglBadCurrentSurface = priv::ErrorStream<EGL_BAD_CURRENT_SURFACE>;
205 using EglBadDisplay        = priv::ErrorStream<EGL_BAD_DISPLAY>;
206 using EglBadMatch          = priv::ErrorStream<EGL_BAD_MATCH>;
207 using EglBadNativeWindow   = priv::ErrorStream<EGL_BAD_NATIVE_WINDOW>;
208 using EglBadParameter      = priv::ErrorStream<EGL_BAD_PARAMETER>;
209 using EglBadSurface        = priv::ErrorStream<EGL_BAD_SURFACE>;
210 using EglContextLost       = priv::ErrorStream<EGL_CONTEXT_LOST>;
211 using EglBadStream         = priv::ErrorStream<EGL_BAD_STREAM_KHR>;
212 using EglBadState          = priv::ErrorStream<EGL_BAD_STATE_KHR>;
213 using EglBadDevice         = priv::ErrorStream<EGL_BAD_DEVICE_EXT>;
214 
NoError()215 inline Error NoError()
216 {
217     return Error(EGL_SUCCESS);
218 }
219 
220 }  // namespace egl
221 
222 #define ANGLE_CONCAT1(x, y) x##y
223 #define ANGLE_CONCAT2(x, y) ANGLE_CONCAT1(x, y)
224 #define ANGLE_LOCAL_VAR ANGLE_CONCAT2(_localVar, __LINE__)
225 
226 #define ANGLE_TRY_TEMPLATE(EXPR, FUNC) \
227     {                                  \
228         auto ANGLE_LOCAL_VAR = EXPR;   \
229         if (ANGLE_LOCAL_VAR.isError()) \
230         {                              \
231             FUNC(ANGLE_LOCAL_VAR);     \
232         }                              \
233     }                                  \
234     ANGLE_EMPTY_STATEMENT
235 
236 #define ANGLE_RETURN(X) return X;
237 #define ANGLE_TRY(EXPR) ANGLE_TRY_TEMPLATE(EXPR, ANGLE_RETURN);
238 
239 #define ANGLE_TRY_RESULT(EXPR, RESULT)         \
240     {                                          \
241         auto ANGLE_LOCAL_VAR = EXPR;           \
242         if (ANGLE_LOCAL_VAR.isError())         \
243         {                                      \
244             return ANGLE_LOCAL_VAR.getError(); \
245         }                                      \
246         RESULT = ANGLE_LOCAL_VAR.getResult();  \
247     }                                          \
248     ANGLE_EMPTY_STATEMENT
249 
250 // TODO(jmadill): Introduce way to store errors to a const Context.
251 #define ANGLE_SWALLOW_ERR(EXPR)                                       \
252     {                                                                 \
253         auto ANGLE_LOCAL_VAR = EXPR;                                  \
254         if (ANGLE_LOCAL_VAR.isError())                                \
255         {                                                             \
256             ERR() << "Unhandled internal error: " << ANGLE_LOCAL_VAR; \
257         }                                                             \
258     }                                                                 \
259     ANGLE_EMPTY_STATEMENT
260 
261 #undef ANGLE_LOCAL_VAR
262 #undef ANGLE_CONCAT2
263 #undef ANGLE_CONCAT1
264 
265 #include "Error.inl"
266 
267 #endif // LIBANGLE_ERROR_H_
268