1 //
2 // Copyright 2015 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
7 // validationEGL.h: Validation functions for generic EGL entry point parameters
8
9 #ifndef LIBANGLE_VALIDATIONEGL_H_
10 #define LIBANGLE_VALIDATIONEGL_H_
11
12 #include "common/PackedEnums.h"
13 #include "libANGLE/Display.h"
14 #include "libANGLE/Error.h"
15 #include "libANGLE/Thread.h"
16
17 #include <EGL/egl.h>
18 #include <EGL/eglext.h>
19
20 namespace gl
21 {
22 class Context;
23 }
24
25 namespace egl
26 {
27 constexpr EGLint kEglMajorVersion = 1;
28 constexpr EGLint kEglMinorVersion = 5;
29
30 class AttributeMap;
31 struct ClientExtensions;
32 struct Config;
33 class Device;
34 class Display;
35 class Image;
36 class Stream;
37 class Surface;
38 class Sync;
39 class Thread;
40 class LabeledObject;
41
42 struct ValidationContext
43 {
ValidationContextValidationContext44 ValidationContext(Thread *threadIn, const char *entryPointIn, const LabeledObject *objectIn)
45 : eglThread(threadIn), entryPoint(entryPointIn), labeledObject(objectIn)
46 {}
47
48 // We should remove the message-less overload once we have messages for all EGL errors.
49 void setError(EGLint error) const;
50 ANGLE_FORMAT_PRINTF(3, 4)
51 void setError(EGLint error, const char *message...) const;
52
53 Thread *eglThread;
54 const char *entryPoint;
55 const LabeledObject *labeledObject;
56 };
57
58 // Object validation
59 bool ValidateDisplay(const ValidationContext *val, const Display *display);
60 bool ValidateSurface(const ValidationContext *val, const Display *display, SurfaceID surfaceID);
61 bool ValidateConfig(const ValidationContext *val, const Display *display, const Config *config);
62 bool ValidateContext(const ValidationContext *val, const Display *display, gl::ContextID contextID);
63 bool ValidateImage(const ValidationContext *val, const Display *display, ImageID imageID);
64 bool ValidateDevice(const ValidationContext *val, const Device *device);
65 bool ValidateSync(const ValidationContext *val, const Display *display, SyncID sync);
66
67 // Return the requested object only if it is valid (otherwise nullptr)
68 const Thread *GetThreadIfValid(const Thread *thread);
69 const Display *GetDisplayIfValid(const Display *display);
70 const Surface *GetSurfaceIfValid(const Display *display, SurfaceID surfaceID);
71 const Image *GetImageIfValid(const Display *display, ImageID imageID);
72 const Stream *GetStreamIfValid(const Display *display, const Stream *stream);
73 const gl::Context *GetContextIfValid(const Display *display, gl::ContextID contextID);
74 gl::Context *GetContextIfValid(Display *display, gl::ContextID contextID);
75 const Device *GetDeviceIfValid(const Device *device);
76 const Sync *GetSyncIfValid(const Display *display, SyncID sync);
77 const LabeledObject *GetLabeledObjectIfValid(Thread *thread,
78 const Display *display,
79 ObjectType objectType,
80 EGLObjectKHR object);
81 LabeledObject *GetLabeledObjectIfValid(Thread *thread,
82 Display *display,
83 ObjectType objectType,
84 EGLObjectKHR object);
85
86 // A template struct for determining the default value to return for each entry point.
87 template <angle::EntryPoint EP, typename ReturnType>
88 struct DefaultReturnValue
89 {
90 static constexpr ReturnType kValue = static_cast<ReturnType>(0);
91 };
92
93 template <angle::EntryPoint EP, typename ReturnType>
94 ReturnType GetDefaultReturnValue(Thread *thread);
95
96 template <>
97 ANGLE_INLINE EGLint
98 GetDefaultReturnValue<angle::EntryPoint::EGLLabelObjectKHR, EGLint>(Thread *thread)
99 {
100 return thread->getError();
101 }
102
103 template <angle::EntryPoint EP, typename ReturnType>
GetDefaultReturnValue(Thread * thread)104 ANGLE_INLINE ReturnType GetDefaultReturnValue(Thread *thread)
105 {
106 return DefaultReturnValue<EP, ReturnType>::kValue;
107 }
108
109 // First case: handling packed enums.
110 template <typename PackedT, typename FromT>
PackParam(FromT from)111 typename std::enable_if<std::is_enum<PackedT>::value, PackedT>::type PackParam(FromT from)
112 {
113 return FromEGLenum<PackedT>(from);
114 }
115
116 // Second case: handling resource ids.
117 template <typename PackedT,
118 typename FromT,
119 typename std::enable_if<IsResourceIDType<PackedT>::value>::type * = nullptr>
PackParam(FromT from)120 PackedT PackParam(FromT from)
121 {
122 return {static_cast<GLuint>(reinterpret_cast<uintptr_t>(from))};
123 }
124
125 // This and the next 2 template specializations handle distinguishing between EGLint, EGLAttrib
126 // and other. This is needed because on some architectures EGLint and EGLAttrib are not the same
127 // base type. Previously the code conditionally compiled 2 specializations on 64 bit but it turns
128 // out on WatchOS the assumption about 32/64 bit and if EGLint and ELGAttrib are the same or
129 // different did not hold.
130 template <typename PackedT,
131 typename FromT,
132 typename std::enable_if<!std::is_enum<PackedT>::value>::type * = nullptr,
133 typename std::enable_if<std::is_same<FromT, const EGLint *>::value>::type * = nullptr>
PackParam(FromT attribs)134 typename std::remove_reference<PackedT>::type PackParam(FromT attribs)
135 {
136 return AttributeMap::CreateFromIntArray(attribs);
137 }
138
139 template <typename PackedT,
140 typename FromT,
141 typename std::enable_if<!std::is_enum<PackedT>::value>::type * = nullptr,
142 typename std::enable_if<!std::is_same<FromT, const EGLint *>::value>::type * = nullptr,
143 typename std::enable_if<std::is_same<FromT, const EGLAttrib *>::value>::type * = nullptr>
PackParam(FromT attribs)144 typename std::remove_reference<PackedT>::type PackParam(FromT attribs)
145 {
146 return AttributeMap::CreateFromAttribArray(attribs);
147 }
148
149 template <typename PackedT,
150 typename FromT,
151 typename std::enable_if<!std::is_enum<PackedT>::value>::type * = nullptr,
152 typename std::enable_if<!std::is_same<FromT, const EGLint *>::value>::type * = nullptr,
153 typename std::enable_if<!std::is_same<FromT, const EGLAttrib *>::value>::type * = nullptr,
154 typename std::enable_if<!IsResourceIDType<PackedT>::value>::type * = nullptr>
PackParam(FromT from)155 typename std::remove_reference<PackedT>::type PackParam(FromT from)
156 {
157 return static_cast<PackedT>(from);
158 }
159
160 } // namespace egl
161
162 #define ANGLE_EGL_VALIDATE(THREAD, EP, OBJ, RETURN_TYPE, ...) \
163 do \
164 { \
165 const char *epname = "egl" #EP; \
166 ValidationContext vctx(THREAD, epname, OBJ); \
167 auto ANGLE_LOCAL_VAR = (Validate##EP(&vctx, ##__VA_ARGS__)); \
168 if (!ANGLE_LOCAL_VAR) \
169 { \
170 return GetDefaultReturnValue<angle::EntryPoint::EGL##EP, RETURN_TYPE>(THREAD); \
171 } \
172 } while (0)
173
174 #define ANGLE_EGL_VALIDATE_VOID(THREAD, EP, OBJ, ...) \
175 do \
176 { \
177 const char *epname = "egl" #EP; \
178 ValidationContext vctx(THREAD, epname, OBJ); \
179 auto ANGLE_LOCAL_VAR = (Validate##EP(&vctx, ##__VA_ARGS__)); \
180 if (!ANGLE_LOCAL_VAR) \
181 { \
182 return; \
183 } \
184 } while (0)
185
186 #define ANGLE_EGL_TRY(THREAD, EXPR, FUNCNAME, LABELOBJECT) \
187 do \
188 { \
189 auto ANGLE_LOCAL_VAR = (EXPR); \
190 if (ANGLE_LOCAL_VAR.isError()) \
191 return THREAD->setError(ANGLE_LOCAL_VAR, FUNCNAME, LABELOBJECT); \
192 } while (0)
193
194 #define ANGLE_EGL_TRY_RETURN(THREAD, EXPR, FUNCNAME, LABELOBJECT, RETVAL) \
195 do \
196 { \
197 auto ANGLE_LOCAL_VAR = (EXPR); \
198 if (ANGLE_LOCAL_VAR.isError()) \
199 { \
200 THREAD->setError(ANGLE_LOCAL_VAR, FUNCNAME, LABELOBJECT); \
201 return RETVAL; \
202 } \
203 } while (0)
204
205 #if ANGLE_USE_DISPLAY_PREPARE_FOR_CALL
206 # define ANGLE_EGL_TRY_PREPARE_FOR_CALL_RETURN ANGLE_EGL_TRY_RETURN
207 # define ANGLE_EGL_TRY_PREPARE_FOR_CALL ANGLE_EGL_TRY
208 #else
209 # define ANGLE_EGL_TRY_PREPARE_FOR_CALL_RETURN(...)
210 # define ANGLE_EGL_TRY_PREPARE_FOR_CALL(...)
211 #endif
212
213 #define ANGLE_EGLBOOLEAN_TRY(EXPR) \
214 do \
215 { \
216 EGLBoolean ANGLE_LOCAL_VAR = (EXPR); \
217 if (ANGLE_LOCAL_VAR != EGL_TRUE) \
218 { \
219 return ANGLE_LOCAL_VAR; \
220 } \
221 } while (0)
222
223 #endif // LIBANGLE_VALIDATIONEGL_H_
224