xref: /aosp_15_r20/external/tensorflow/tensorflow/lite/delegates/gpu/gl/egl_environment.cc (revision b6fb3261f9314811a0f4371741dbb8839866f948)
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_environment.h"
17 
18 #include <memory>
19 
20 #include "absl/memory/memory.h"
21 #include "tensorflow/lite/delegates/gpu/common/status.h"
22 #include "tensorflow/lite/delegates/gpu/gl/gl_call.h"
23 #include "tensorflow/lite/delegates/gpu/gl/request_gpu_info.h"
24 
25 namespace tflite {
26 namespace gpu {
27 namespace gl {
28 namespace {
29 
30 // TODO(akulik): detect power management event when all contexts are destroyed
31 // and OpenGL ES is reinitialized. See eglMakeCurrent
32 
InitDisplay(EGLDisplay * egl_display)33 absl::Status InitDisplay(EGLDisplay* egl_display) {
34   RETURN_IF_ERROR(
35       TFLITE_GPU_CALL_EGL(eglGetDisplay, egl_display, EGL_DEFAULT_DISPLAY));
36   if (*egl_display == EGL_NO_DISPLAY) {
37     return absl::UnavailableError("eglGetDisplay returned nullptr");
38   }
39   bool is_initialized;
40   RETURN_IF_ERROR(TFLITE_GPU_CALL_EGL(eglInitialize, &is_initialized,
41                                       *egl_display, nullptr, nullptr));
42   if (!is_initialized) {
43     return absl::InternalError("No EGL error, but eglInitialize failed");
44   }
45   return absl::OkStatus();
46 }
47 
48 }  // namespace
49 
NewEglEnvironment(std::unique_ptr<EglEnvironment> * egl_environment)50 absl::Status EglEnvironment::NewEglEnvironment(
51     std::unique_ptr<EglEnvironment>* egl_environment) {
52   *egl_environment = std::make_unique<EglEnvironment>();
53   RETURN_IF_ERROR((*egl_environment)->Init());
54   return absl::OkStatus();
55 }
56 
~EglEnvironment()57 EglEnvironment::~EglEnvironment() {
58   if (dummy_framebuffer_ != GL_INVALID_INDEX) {
59     glDeleteFramebuffers(1, &dummy_framebuffer_);
60   }
61   if (dummy_texture_ != GL_INVALID_INDEX) {
62     glDeleteTextures(1, &dummy_texture_);
63   }
64 }
65 
Init()66 absl::Status EglEnvironment::Init() {
67   bool is_bound;
68   RETURN_IF_ERROR(
69       TFLITE_GPU_CALL_EGL(eglBindAPI, &is_bound, EGL_OPENGL_ES_API));
70   if (!is_bound) {
71     return absl::InternalError("No EGL error, but eglBindAPI failed");
72   }
73 
74   // Re-use context and display if it was created on this thread.
75   if (eglGetCurrentContext() != EGL_NO_CONTEXT) {
76     display_ = eglGetCurrentDisplay();
77     context_ =
78         EglContext(eglGetCurrentContext(), display_, EGL_NO_CONFIG_KHR, false);
79   } else {
80     RETURN_IF_ERROR(InitDisplay(&display_));
81 
82     absl::Status status = InitConfiglessContext();
83     if (!status.ok()) {
84       status = InitSurfacelessContext();
85     }
86     if (!status.ok()) {
87       status = InitPBufferContext();
88     }
89     if (!status.ok()) {
90       return status;
91     }
92   }
93 
94   if (gpu_info_.vendor == GpuVendor::kUnknown) {
95     RETURN_IF_ERROR(RequestGpuInfo(&gpu_info_));
96   }
97   // TODO(akulik): when do we need ForceSyncTurning?
98   ForceSyncTurning();
99   return absl::OkStatus();
100 }
101 
InitConfiglessContext()102 absl::Status EglEnvironment::InitConfiglessContext() {
103   RETURN_IF_ERROR(CreateConfiglessContext(display_, EGL_NO_CONTEXT, &context_));
104   return context_.MakeCurrentSurfaceless();
105 }
106 
InitSurfacelessContext()107 absl::Status EglEnvironment::InitSurfacelessContext() {
108   RETURN_IF_ERROR(
109       CreateSurfacelessContext(display_, EGL_NO_CONTEXT, &context_));
110   RETURN_IF_ERROR(context_.MakeCurrentSurfaceless());
111 
112   // PowerVR support EGL_KHR_surfaceless_context, but glFenceSync crashes on
113   // PowerVR when it is surface-less.
114   RETURN_IF_ERROR(RequestGpuInfo(&gpu_info_));
115   if (gpu_info_.IsPowerVR()) {
116     return absl::UnavailableError(
117         "Surface-less context is not properly supported on powervr.");
118   }
119   return absl::OkStatus();
120 }
121 
InitPBufferContext()122 absl::Status EglEnvironment::InitPBufferContext() {
123   RETURN_IF_ERROR(CreatePBufferContext(display_, EGL_NO_CONTEXT, &context_));
124   RETURN_IF_ERROR(CreatePbufferRGBSurface(context_.config(), display_, 1, 1,
125                                           &surface_read_));
126   RETURN_IF_ERROR(CreatePbufferRGBSurface(context_.config(), display_, 1, 1,
127                                           &surface_draw_));
128   return context_.MakeCurrent(surface_read_.surface(), surface_draw_.surface());
129 }
130 
ForceSyncTurning()131 void EglEnvironment::ForceSyncTurning() {
132   glGenFramebuffers(1, &dummy_framebuffer_);
133   glBindFramebuffer(GL_FRAMEBUFFER, dummy_framebuffer_);
134 
135   glGenTextures(1, &dummy_texture_);
136   glBindTexture(GL_TEXTURE_2D, dummy_texture_);
137   glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 4, 4);
138   glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
139                          dummy_texture_, 0);
140 
141   GLenum draw_buffers[1] = {GL_COLOR_ATTACHMENT0};
142   glDrawBuffers(1, draw_buffers);
143 
144   glViewport(0, 0, 4, 4);
145   glClear(GL_COLOR_BUFFER_BIT);
146 }
147 
148 }  // namespace gl
149 }  // namespace gpu
150 }  // namespace tflite
151