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/gl/egl_context.h"
17
18 #include <cstring>
19
20 #include "tensorflow/lite/delegates/gpu/common/status.h"
21 #include "tensorflow/lite/delegates/gpu/gl/gl_call.h"
22 #include "tensorflow/lite/delegates/gpu/gl/gl_errors.h"
23
24 namespace tflite {
25 namespace gpu {
26 namespace gl {
27 namespace {
28
GetConfig(EGLDisplay display,const EGLint * attributes,EGLConfig * config)29 absl::Status GetConfig(EGLDisplay display, const EGLint* attributes,
30 EGLConfig* config) {
31 EGLint config_count;
32 bool chosen = eglChooseConfig(display, attributes, config, 1, &config_count);
33 RETURN_IF_ERROR(GetOpenGlErrors());
34 if (!chosen || config_count == 0) {
35 return absl::InternalError("No EGL error, but eglChooseConfig failed.");
36 }
37 return absl::OkStatus();
38 }
39
CreateContext(EGLDisplay display,EGLContext shared_context,EGLConfig config,EglContext * egl_context)40 absl::Status CreateContext(EGLDisplay display, EGLContext shared_context,
41 EGLConfig config, EglContext* egl_context) {
42 static const EGLint attributes[] = {EGL_CONTEXT_CLIENT_VERSION, 3,
43 #ifdef _DEBUG // Add debugging bit
44 EGL_CONTEXT_FLAGS_KHR,
45 EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR,
46 #endif
47 EGL_NONE};
48 EGLContext context =
49 eglCreateContext(display, config, shared_context, attributes);
50 RETURN_IF_ERROR(GetOpenGlErrors());
51 if (context == EGL_NO_CONTEXT) {
52 return absl::InternalError("No EGL error, but eglCreateContext failed.");
53 }
54 *egl_context = EglContext(context, display, config, true);
55 return absl::OkStatus();
56 }
57
HasExtension(EGLDisplay display,const char * name)58 bool HasExtension(EGLDisplay display, const char* name) {
59 return std::strstr(eglQueryString(display, EGL_EXTENSIONS), name);
60 }
61
62 } // namespace
63
Invalidate()64 void EglContext::Invalidate() {
65 if (context_ != EGL_NO_CONTEXT) {
66 if (has_ownership_) {
67 eglMakeCurrent(display_, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
68 eglDestroyContext(display_, context_);
69 }
70 context_ = EGL_NO_CONTEXT;
71 }
72 has_ownership_ = false;
73 }
74
EglContext(EglContext && other)75 EglContext::EglContext(EglContext&& other)
76 : context_(other.context_),
77 display_(other.display_),
78 config_(other.config_),
79 has_ownership_(other.has_ownership_) {
80 other.context_ = EGL_NO_CONTEXT;
81 other.has_ownership_ = false;
82 }
83
operator =(EglContext && other)84 EglContext& EglContext::operator=(EglContext&& other) {
85 if (this != &other) {
86 Invalidate();
87 using std::swap;
88 swap(context_, other.context_);
89 display_ = other.display_;
90 config_ = other.config_;
91 swap(has_ownership_, other.has_ownership_);
92 }
93 return *this;
94 }
95
MakeCurrent(EGLSurface read,EGLSurface write)96 absl::Status EglContext::MakeCurrent(EGLSurface read, EGLSurface write) {
97 bool is_made_current = eglMakeCurrent(display_, write, read, context_);
98 RETURN_IF_ERROR(GetOpenGlErrors());
99 if (!is_made_current) {
100 return absl::InternalError("No EGL error, but eglMakeCurrent failed.");
101 }
102 return absl::OkStatus();
103 }
104
IsCurrent() const105 bool EglContext::IsCurrent() const {
106 return context_ == eglGetCurrentContext();
107 }
108
CreateConfiglessContext(EGLDisplay display,EGLContext shared_context,EglContext * egl_context)109 absl::Status CreateConfiglessContext(EGLDisplay display,
110 EGLContext shared_context,
111 EglContext* egl_context) {
112 if (!HasExtension(display, "EGL_KHR_no_config_context")) {
113 return absl::UnavailableError("EGL_KHR_no_config_context not supported");
114 }
115 return CreateContext(display, shared_context, EGL_NO_CONFIG_KHR, egl_context);
116 }
117
CreateSurfacelessContext(EGLDisplay display,EGLContext shared_context,EglContext * egl_context)118 absl::Status CreateSurfacelessContext(EGLDisplay display,
119 EGLContext shared_context,
120 EglContext* egl_context) {
121 if (!HasExtension(display, "EGL_KHR_create_context")) {
122 return absl::UnavailableError("EGL_KHR_create_context not supported");
123 }
124 if (!HasExtension(display, "EGL_KHR_surfaceless_context")) {
125 return absl::UnavailableError("EGL_KHR_surfaceless_context not supported");
126 }
127 const EGLint attributes[] = {EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT_KHR,
128 EGL_NONE};
129 EGLConfig config;
130 RETURN_IF_ERROR(GetConfig(display, attributes, &config));
131 return CreateContext(display, shared_context, config, egl_context);
132 }
133
CreatePBufferContext(EGLDisplay display,EGLContext shared_context,EglContext * egl_context)134 absl::Status CreatePBufferContext(EGLDisplay display, EGLContext shared_context,
135 EglContext* egl_context) {
136 const EGLint attributes[] = {
137 EGL_SURFACE_TYPE, EGL_PBUFFER_BIT, EGL_BIND_TO_TEXTURE_RGB,
138 EGL_TRUE, EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT_KHR,
139 EGL_NONE};
140 EGLConfig config;
141 RETURN_IF_ERROR(GetConfig(display, attributes, &config));
142 return CreateContext(display, shared_context, config, egl_context);
143 }
144
145 } // namespace gl
146 } // namespace gpu
147 } // namespace tflite
148