1 //
2 // Copyright 2016 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 // SurfaceEGL.cpp: EGL implementation of egl::Surface
8
9 #include "libANGLE/renderer/gl/egl/SurfaceEGL.h"
10
11 #include "common/debug.h"
12 #include "libANGLE/Display.h"
13
14 namespace rx
15 {
16
SurfaceEGL(const egl::SurfaceState & state,const FunctionsEGL * egl,EGLConfig config)17 SurfaceEGL::SurfaceEGL(const egl::SurfaceState &state, const FunctionsEGL *egl, EGLConfig config)
18 : SurfaceGL(state),
19 mEGL(egl),
20 mConfig(config),
21 mSurface(EGL_NO_SURFACE),
22 mHasSwapBuffersWithDamage(mEGL->hasExtension("EGL_KHR_swap_buffers_with_damage"))
23 {}
24
~SurfaceEGL()25 SurfaceEGL::~SurfaceEGL()
26 {
27 if (mSurface != EGL_NO_SURFACE)
28 {
29 EGLBoolean success = mEGL->destroySurface(mSurface);
30 ASSERT(success == EGL_TRUE);
31 }
32 }
33
makeCurrent(const gl::Context * context)34 egl::Error SurfaceEGL::makeCurrent(const gl::Context *context)
35 {
36 // Handling of makeCurrent is done in DisplayEGL
37 return egl::NoError();
38 }
39
swap(const gl::Context * context)40 egl::Error SurfaceEGL::swap(const gl::Context *context)
41 {
42 egl::Display::GetCurrentThreadUnlockedTailCall()->add(
43 [egl = mEGL, surface = mSurface](void *resultOut) {
44 ANGLE_UNUSED_VARIABLE(resultOut);
45 *static_cast<EGLBoolean *>(resultOut) = egl->swapBuffers(surface);
46 });
47
48 return egl::NoError();
49 }
50
swapWithDamage(const gl::Context * context,const EGLint * rects,EGLint n_rects)51 egl::Error SurfaceEGL::swapWithDamage(const gl::Context *context,
52 const EGLint *rects,
53 EGLint n_rects)
54 {
55 if (mHasSwapBuffersWithDamage)
56 {
57 egl::Display::GetCurrentThreadUnlockedTailCall()->add(
58 [egl = mEGL, surface = mSurface, rects, n_rects](void *resultOut) {
59 ANGLE_UNUSED_VARIABLE(resultOut);
60 *static_cast<EGLBoolean *>(resultOut) =
61 egl->swapBuffersWithDamageKHR(surface, rects, n_rects);
62 });
63 }
64 else
65 {
66 egl::Display::GetCurrentThreadUnlockedTailCall()->add(
67 [egl = mEGL, surface = mSurface](void *resultOut) {
68 ANGLE_UNUSED_VARIABLE(resultOut);
69 *static_cast<EGLBoolean *>(resultOut) = egl->swapBuffers(surface);
70 });
71 }
72
73 return egl::NoError();
74 }
75
postSubBuffer(const gl::Context * context,EGLint x,EGLint y,EGLint width,EGLint height)76 egl::Error SurfaceEGL::postSubBuffer(const gl::Context *context,
77 EGLint x,
78 EGLint y,
79 EGLint width,
80 EGLint height)
81 {
82 UNIMPLEMENTED();
83 return egl::EglBadSurface();
84 }
85
setPresentationTime(EGLnsecsANDROID time)86 egl::Error SurfaceEGL::setPresentationTime(EGLnsecsANDROID time)
87 {
88 EGLBoolean success = mEGL->presentationTimeANDROID(mSurface, time);
89 if (success == EGL_FALSE)
90 {
91 return egl::Error(mEGL->getError(), "eglPresentationTimeANDROID failed");
92 }
93 return egl::NoError();
94 }
95
querySurfacePointerANGLE(EGLint attribute,void ** value)96 egl::Error SurfaceEGL::querySurfacePointerANGLE(EGLint attribute, void **value)
97 {
98 UNIMPLEMENTED();
99 return egl::EglBadSurface();
100 }
101
bindTexImage(const gl::Context * context,gl::Texture * texture,EGLint buffer)102 egl::Error SurfaceEGL::bindTexImage(const gl::Context *context, gl::Texture *texture, EGLint buffer)
103 {
104 EGLBoolean success = mEGL->bindTexImage(mSurface, buffer);
105 if (success == EGL_FALSE)
106 {
107 return egl::Error(mEGL->getError(), "eglBindTexImage failed");
108 }
109 return egl::NoError();
110 }
111
releaseTexImage(const gl::Context * context,EGLint buffer)112 egl::Error SurfaceEGL::releaseTexImage(const gl::Context *context, EGLint buffer)
113 {
114 EGLBoolean success = mEGL->releaseTexImage(mSurface, buffer);
115 if (success == EGL_FALSE)
116 {
117 return egl::Error(mEGL->getError(), "eglReleaseTexImage failed");
118 }
119 return egl::NoError();
120 }
121
setSwapInterval(const egl::Display * display,EGLint interval)122 void SurfaceEGL::setSwapInterval(const egl::Display *display, EGLint interval)
123 {
124 EGLBoolean success = mEGL->swapInterval(interval);
125 if (success == EGL_FALSE)
126 {
127 ERR() << "eglSwapInterval error " << egl::Error(mEGL->getError());
128 ASSERT(false);
129 }
130 }
131
getWidth() const132 EGLint SurfaceEGL::getWidth() const
133 {
134 EGLint value;
135 EGLBoolean success = mEGL->querySurface(mSurface, EGL_WIDTH, &value);
136 ASSERT(success == EGL_TRUE);
137 return value;
138 }
139
getHeight() const140 EGLint SurfaceEGL::getHeight() const
141 {
142 EGLint value;
143 EGLBoolean success = mEGL->querySurface(mSurface, EGL_HEIGHT, &value);
144 ASSERT(success == EGL_TRUE);
145 return value;
146 }
147
isPostSubBufferSupported() const148 EGLint SurfaceEGL::isPostSubBufferSupported() const
149 {
150 UNIMPLEMENTED();
151 return 0;
152 }
153
getSwapBehavior() const154 EGLint SurfaceEGL::getSwapBehavior() const
155 {
156 EGLint value;
157 EGLBoolean success = mEGL->querySurface(mSurface, EGL_SWAP_BEHAVIOR, &value);
158 ASSERT(success == EGL_TRUE);
159 return value;
160 }
161
getSurface() const162 EGLSurface SurfaceEGL::getSurface() const
163 {
164 return mSurface;
165 }
166
setTimestampsEnabled(bool enabled)167 void SurfaceEGL::setTimestampsEnabled(bool enabled)
168 {
169 ASSERT(mEGL->hasExtension("EGL_ANDROID_get_frame_timestamps"));
170
171 EGLBoolean success =
172 mEGL->surfaceAttrib(mSurface, EGL_TIMESTAMPS_ANDROID, enabled ? EGL_TRUE : EGL_FALSE);
173 if (success == EGL_FALSE)
174 {
175 ERR() << "eglSurfaceAttribute failed: " << egl::Error(mEGL->getError());
176 }
177 }
178
getSupportedCompositorTimings() const179 egl::SupportedCompositorTimings SurfaceEGL::getSupportedCompositorTimings() const
180 {
181 ASSERT(mEGL->hasExtension("EGL_ANDROID_get_frame_timestamps"));
182
183 egl::SupportedCompositorTimings result;
184 for (egl::CompositorTiming name : angle::AllEnums<egl::CompositorTiming>())
185 {
186 result[name] = mEGL->getCompositorTimingSupportedANDROID(mSurface, egl::ToEGLenum(name));
187 }
188 return result;
189 }
190
getCompositorTiming(EGLint numTimestamps,const EGLint * names,EGLnsecsANDROID * values) const191 egl::Error SurfaceEGL::getCompositorTiming(EGLint numTimestamps,
192 const EGLint *names,
193 EGLnsecsANDROID *values) const
194 {
195 ASSERT(mEGL->hasExtension("EGL_ANDROID_get_frame_timestamps"));
196
197 egl::Display::GetCurrentThreadUnlockedTailCall()->add(
198 [egl = mEGL, surface = mSurface, numTimestamps, names, values](void *resultOut) {
199 EGLBoolean success =
200 egl->getCompositorTimingANDROID(surface, numTimestamps, names, values);
201 if (!success)
202 {
203 ERR() << "eglGetCompositorTimingANDROID failed: " << egl::Error(egl->getError());
204 }
205 *static_cast<EGLBoolean *>(resultOut) = success;
206 });
207
208 return egl::NoError();
209 }
210
getNextFrameId(EGLuint64KHR * frameId) const211 egl::Error SurfaceEGL::getNextFrameId(EGLuint64KHR *frameId) const
212 {
213 ASSERT(mEGL->hasExtension("EGL_ANDROID_get_frame_timestamps"));
214
215 EGLBoolean success = mEGL->getNextFrameIdANDROID(mSurface, frameId);
216 if (success == EGL_FALSE)
217 {
218 return egl::Error(mEGL->getError(), "eglGetNextFrameId failed");
219 }
220 return egl::NoError();
221 }
222
getSupportedTimestamps() const223 egl::SupportedTimestamps SurfaceEGL::getSupportedTimestamps() const
224 {
225 ASSERT(mEGL->hasExtension("EGL_ANDROID_get_frame_timestamps"));
226
227 egl::SupportedTimestamps result;
228 for (egl::Timestamp timestamp : angle::AllEnums<egl::Timestamp>())
229 {
230 result[timestamp] =
231 mEGL->getFrameTimestampSupportedANDROID(mSurface, egl::ToEGLenum(timestamp));
232 }
233 return result;
234 }
235
getFrameTimestamps(EGLuint64KHR frameId,EGLint numTimestamps,const EGLint * timestamps,EGLnsecsANDROID * values) const236 egl::Error SurfaceEGL::getFrameTimestamps(EGLuint64KHR frameId,
237 EGLint numTimestamps,
238 const EGLint *timestamps,
239 EGLnsecsANDROID *values) const
240 {
241 ASSERT(mEGL->hasExtension("EGL_ANDROID_get_frame_timestamps"));
242
243 egl::Display::GetCurrentThreadUnlockedTailCall()->add([egl = mEGL, surface = mSurface, frameId,
244 numTimestamps, timestamps,
245 values](void *resultOut) {
246 EGLBoolean success =
247 egl->getFrameTimestampsANDROID(surface, frameId, numTimestamps, timestamps, values);
248 if (!success)
249 {
250 // The driver may return EGL_BAD_ACCESS at any time if the requested frame is no longer
251 // stored.
252 ERR() << "eglGetFrameTimestampsANDROID failed: " << egl::Error(egl->getError());
253 }
254 *static_cast<EGLBoolean *>(resultOut) = success;
255 });
256
257 return egl::NoError();
258 }
259
isExternal() const260 bool SurfaceEGL::isExternal() const
261 {
262 return false;
263 }
264
265 } // namespace rx
266