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