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