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