1 /* Copyright 2019 The TensorFlow Authors. All Rights Reserved.
2
3 Licensed under the Apache License, Version 2.0 (the "License");
4 you may not use this file except in compliance with the License.
5 You may obtain a copy of the License at
6
7 http://www.apache.org/licenses/LICENSE-2.0
8
9 Unless required by applicable law or agreed to in writing, software
10 distributed under the License is distributed on an "AS IS" BASIS,
11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 See the License for the specific language governing permissions and
13 limitations under the License.
14 ==============================================================================*/
15
16 #include "tensorflow/lite/delegates/gpu/cl/egl_sync.h"
17
18 #include "tensorflow/lite/delegates/gpu/gl/gl_call.h"
19
20 namespace tflite {
21 namespace gpu {
22 namespace cl {
23
24 namespace {
25
HasExtension(EGLDisplay display,const char * extension)26 bool HasExtension(EGLDisplay display, const char* extension) {
27 const char* extensions = eglQueryString(display, EGL_EXTENSIONS);
28 return extensions && std::strstr(extensions, extension);
29 }
30
IsEglFenceSyncSupported(EGLDisplay display)31 absl::Status IsEglFenceSyncSupported(EGLDisplay display) {
32 static bool supported = HasExtension(display, "EGL_KHR_fence_sync");
33 if (supported) {
34 return absl::OkStatus();
35 }
36 return absl::InternalError("Not supported: EGL_KHR_fence_sync");
37 }
38
IsEglWaitSyncSupported(EGLDisplay display)39 absl::Status IsEglWaitSyncSupported(EGLDisplay display) {
40 static bool supported = HasExtension(display, "EGL_KHR_wait_sync");
41 if (supported) {
42 return absl::OkStatus();
43 }
44 return absl::InternalError("Not supported: EGL_KHR_wait_sync");
45 }
46
47 } // anonymous namespace
48
NewFence(EGLDisplay display,EglSync * sync)49 absl::Status EglSync::NewFence(EGLDisplay display, EglSync* sync) {
50 RETURN_IF_ERROR(IsEglFenceSyncSupported(display));
51 static auto* egl_create_sync_khr =
52 reinterpret_cast<decltype(&eglCreateSyncKHR)>(
53 eglGetProcAddress("eglCreateSyncKHR"));
54 if (egl_create_sync_khr == nullptr) {
55 // Needs extension: EGL_KHR_fence_sync (EGL) / GL_OES_EGL_sync (OpenGL ES).
56 return absl::InternalError(
57 "Not supported / bad EGL implementation: eglCreateSyncKHR.");
58 }
59 EGLSyncKHR egl_sync;
60 RETURN_IF_ERROR(TFLITE_GPU_CALL_EGL(*egl_create_sync_khr, &egl_sync, display,
61 EGL_SYNC_FENCE_KHR, nullptr));
62 if (egl_sync == EGL_NO_SYNC_KHR) {
63 return absl::InternalError("Returned empty KHR EGL sync");
64 }
65 *sync = EglSync(display, egl_sync);
66 return absl::OkStatus();
67 }
68
operator =(EglSync && sync)69 EglSync& EglSync::operator=(EglSync&& sync) {
70 if (this != &sync) {
71 Invalidate();
72 std::swap(sync_, sync.sync_);
73 display_ = sync.display_;
74 }
75 return *this;
76 }
77
Invalidate()78 void EglSync::Invalidate() {
79 if (sync_ != EGL_NO_SYNC_KHR) {
80 static auto* egl_destroy_sync_khr =
81 reinterpret_cast<decltype(&eglDestroySyncKHR)>(
82 eglGetProcAddress("eglDestroySyncKHR"));
83 // Needs extension: EGL_KHR_fence_sync (EGL) / GL_OES_EGL_sync (OpenGL ES).
84 if (IsEglFenceSyncSupported(display_).ok() && egl_destroy_sync_khr) {
85 // Note: we're doing nothing when the function pointer is nullptr, or the
86 // call returns EGL_FALSE.
87 (*egl_destroy_sync_khr)(display_, sync_);
88 }
89 sync_ = EGL_NO_SYNC_KHR;
90 }
91 }
92
ServerWait()93 absl::Status EglSync::ServerWait() {
94 RETURN_IF_ERROR(IsEglWaitSyncSupported(display_));
95 static auto* egl_wait_sync_khr = reinterpret_cast<decltype(&eglWaitSyncKHR)>(
96 eglGetProcAddress("eglWaitSyncKHR"));
97 if (egl_wait_sync_khr == nullptr) {
98 // Needs extension: EGL_KHR_wait_sync
99 return absl::InternalError("Not supported: eglWaitSyncKHR.");
100 }
101 EGLint result;
102 RETURN_IF_ERROR(
103 TFLITE_GPU_CALL_EGL(*egl_wait_sync_khr, &result, display_, sync_, 0));
104 return result == EGL_TRUE ? absl::OkStatus()
105 : absl::InternalError("eglWaitSync failed");
106 }
107
ClientWait()108 absl::Status EglSync::ClientWait() {
109 RETURN_IF_ERROR(IsEglFenceSyncSupported(display_));
110 static auto* egl_client_wait_sync_khr =
111 reinterpret_cast<decltype(&eglClientWaitSyncKHR)>(
112 eglGetProcAddress("eglClientWaitSyncKHR"));
113 if (egl_client_wait_sync_khr == nullptr) {
114 // Needs extension: EGL_KHR_fence_sync (EGL) / GL_OES_EGL_sync (OpenGL ES).
115 return absl::InternalError("Not supported: eglClientWaitSyncKHR.");
116 }
117 EGLint result;
118 // TODO(akulik): make it active wait for better performance
119 RETURN_IF_ERROR(
120 TFLITE_GPU_CALL_EGL(*egl_client_wait_sync_khr, &result, display_, sync_,
121 EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, EGL_FOREVER_KHR));
122 return result == EGL_CONDITION_SATISFIED_KHR
123 ? absl::OkStatus()
124 : absl::InternalError("eglClientWaitSync failed");
125 }
126
127 } // namespace cl
128 } // namespace gpu
129 } // namespace tflite
130