xref: /aosp_15_r20/external/tensorflow/tensorflow/lite/delegates/gpu/gl/gl_sync.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/gl_sync.h"
17 
18 #include <string>
19 #include <utility>
20 
21 #ifdef __ARM_ACLE
22 #include <arm_acle.h>
23 #endif  // __ARM_ACLE
24 
25 #include "tensorflow/lite/delegates/gpu/gl/gl_errors.h"
26 
27 namespace tflite {
28 namespace gpu {
29 namespace gl {
30 
GlSyncWait()31 absl::Status GlSyncWait() {
32   GlSync sync;
33   RETURN_IF_ERROR(GlSync::NewSync(&sync));
34   // Flush sync and loop afterwards without it.
35   GLenum status = glClientWaitSync(sync.sync(), GL_SYNC_FLUSH_COMMANDS_BIT,
36                                    /* timeout ns = */ 0);
37   while (true) {
38     switch (status) {
39       case GL_TIMEOUT_EXPIRED:
40         break;
41       case GL_CONDITION_SATISFIED:
42       case GL_ALREADY_SIGNALED:
43         return absl::OkStatus();
44       case GL_WAIT_FAILED:
45         return GetOpenGlErrors();
46     }
47     status = glClientWaitSync(sync.sync(), 0, /* timeout ns = */ 10000000);
48   }
49   return absl::OkStatus();
50 }
51 
GlActiveSyncWait()52 absl::Status GlActiveSyncWait() {
53   GlSync sync;
54   RETURN_IF_ERROR(GlSync::NewSync(&sync));
55   // Since creating a Sync object is itself a GL command it *must* be flushed.
56   // Otherwise glGetSynciv may never succeed. Perform a flush with
57   // glClientWaitSync call.
58   GLenum status = glClientWaitSync(sync.sync(), GL_SYNC_FLUSH_COMMANDS_BIT,
59                                    /* timeout ns = */ 0);
60   switch (status) {
61     case GL_TIMEOUT_EXPIRED:
62       break;
63     case GL_CONDITION_SATISFIED:
64     case GL_ALREADY_SIGNALED:
65       return absl::OkStatus();
66     case GL_WAIT_FAILED:
67       return GetOpenGlErrors();
68   }
69 
70   // Start active loop.
71   GLint result = GL_UNSIGNALED;
72   while (true) {
73     glGetSynciv(sync.sync(), GL_SYNC_STATUS, sizeof(GLint), nullptr, &result);
74     if (result == GL_SIGNALED) {
75       return absl::OkStatus();
76     }
77 #ifdef __ARM_ACLE
78     // Try to save CPU power by yielding CPU to another thread.
79     __yield();
80 #endif
81   }
82 }
83 
NewSync(GlShaderSync * gl_sync)84 absl::Status GlShaderSync::NewSync(GlShaderSync* gl_sync) {
85   GlShaderSync sync;
86   RETURN_IF_ERROR(CreatePersistentBuffer(sizeof(int), &sync.flag_buffer_));
87   static const std::string* kCode = new std::string(R"(#version 310 es
88   layout(local_size_x = 1, local_size_y = 1) in;
89   layout(std430) buffer;
90   layout(binding = 0) buffer Output {
91     int elements[];
92   } output_data;
93   void main() {
94     output_data.elements[0] = 1;
95   })");
96   GlShader shader;
97   RETURN_IF_ERROR(GlShader::CompileShader(GL_COMPUTE_SHADER, *kCode, &shader));
98   RETURN_IF_ERROR(GlProgram::CreateWithShader(shader, &sync.flag_program_));
99   *gl_sync = std::move(sync);
100   return absl::OkStatus();
101 }
102 
103 // How it works: GPU writes a buffer and CPU checks the buffer value to be
104 // changed. The buffer is accessible for writing by GPU and reading by CPU
105 // simultaneously - persistent buffer or buffer across shild context can be used
106 // for that.
Wait()107 absl::Status GlShaderSync::Wait() {
108   if (!flag_buffer_.is_valid()) {
109     return absl::UnavailableError("GlShaderSync is not initialized.");
110   }
111   RETURN_IF_ERROR(flag_buffer_.BindToIndex(0));
112   volatile int* flag_ptr_ = reinterpret_cast<int*>(flag_buffer_.data());
113   *flag_ptr_ = 0;
114   RETURN_IF_ERROR(flag_program_.Dispatch({1, 1, 1}));
115   // glFlush must be called to upload GPU task. Adreno won't start executing
116   // the task without glFlush.
117   glFlush();
118   // Wait for the value is being updated by the shader.
119   while (*flag_ptr_ != 1) {
120   }
121   return absl::OkStatus();
122 }
123 
124 }  // namespace gl
125 }  // namespace gpu
126 }  // namespace tflite
127