xref: /aosp_15_r20/external/tensorflow/tensorflow/lite/delegates/gpu/gl/gl_buffer.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_buffer.h"
17 
18 #include <utility>
19 
20 #include "tensorflow/lite/delegates/gpu/common/status.h"
21 
22 namespace tflite {
23 namespace gpu {
24 namespace gl {
25 
CopyBuffer(const GlBuffer & read_buffer,const GlBuffer & write_buffer)26 absl::Status CopyBuffer(const GlBuffer& read_buffer,
27                         const GlBuffer& write_buffer) {
28   if (read_buffer.bytes_size() != write_buffer.bytes_size()) {
29     return absl::InvalidArgumentError(
30         "Read buffer does not match write buffer size.");
31   }
32   gl_buffer_internal::BufferBinder read_buffer_binder(GL_COPY_READ_BUFFER,
33                                                       read_buffer.id());
34   gl_buffer_internal::BufferBinder write_buffer_binder(GL_COPY_WRITE_BUFFER,
35                                                        write_buffer.id());
36   return TFLITE_GPU_CALL_GL(glCopyBufferSubData, GL_COPY_READ_BUFFER,
37                             GL_COPY_WRITE_BUFFER, read_buffer.offset(),
38                             write_buffer.offset(), read_buffer.bytes_size());
39 }
40 
GetSSBOSize(GLuint id,int64_t * size_bytes)41 absl::Status GetSSBOSize(GLuint id, int64_t* size_bytes) {
42   GLuint prev_id;
43   RETURN_IF_ERROR(TFLITE_GPU_CALL_GL(glGetIntegerv,
44                                      GL_SHADER_STORAGE_BUFFER_BINDING,
45                                      reinterpret_cast<GLint*>(&prev_id)));
46   gl_buffer_internal::BufferBinder binder(GL_SHADER_STORAGE_BUFFER, id,
47                                           prev_id);
48   return TFLITE_GPU_CALL_GL(glGetBufferParameteri64v, GL_SHADER_STORAGE_BUFFER,
49                             GL_BUFFER_SIZE, size_bytes);
50 }
51 
GlBuffer(GlBuffer && buffer)52 GlBuffer::GlBuffer(GlBuffer&& buffer)
53     : GlBuffer(buffer.target_, buffer.id_, buffer.bytes_size_, buffer.offset_,
54                buffer.has_ownership_) {
55   buffer.has_ownership_ = false;
56 }
57 
operator =(GlBuffer && buffer)58 GlBuffer& GlBuffer::operator=(GlBuffer&& buffer) {
59   if (this != &buffer) {
60     Invalidate();
61 
62     target_ = buffer.target_;
63     bytes_size_ = buffer.bytes_size_;
64     offset_ = buffer.offset_;
65     has_ownership_ = buffer.has_ownership_;
66     id_ = buffer.id_;
67     buffer.has_ownership_ = false;
68   }
69   return *this;
70 }
71 
~GlBuffer()72 GlBuffer::~GlBuffer() { Invalidate(); }
73 
Invalidate()74 void GlBuffer::Invalidate() {
75   if (has_ownership_ && id_ != GL_INVALID_INDEX) {
76     TFLITE_GPU_CALL_GL(glDeleteBuffers, 1, &id_).IgnoreError();
77     id_ = GL_INVALID_INDEX;
78   }
79 }
80 
BindToIndex(uint32_t index) const81 absl::Status GlBuffer::BindToIndex(uint32_t index) const {
82   return TFLITE_GPU_CALL_GL(glBindBufferRange, target_, index, id_, offset_,
83                             bytes_size_);
84 }
85 
MakeView(size_t offset,size_t bytes_size,GlBuffer * gl_buffer)86 absl::Status GlBuffer::MakeView(size_t offset, size_t bytes_size,
87                                 GlBuffer* gl_buffer) {
88   if (offset + bytes_size > bytes_size_) {
89     return absl::OutOfRangeError("GlBuffer view is out of range.");
90   }
91   *gl_buffer = GlBuffer(target_, id_, bytes_size, offset_ + offset,
92                         /*has_ownership=*/false);
93   return absl::OkStatus();
94 }
95 
MakeRef()96 GlBuffer GlBuffer::MakeRef() {
97   return GlBuffer(target_, id_, bytes_size_, offset_,
98                   /* has_ownership = */ false);
99 }
100 
GlPersistentBuffer(GLenum target,GLuint id,size_t bytes_size,size_t offset,bool has_ownership,void * data)101 GlPersistentBuffer::GlPersistentBuffer(GLenum target, GLuint id,
102                                        size_t bytes_size, size_t offset,
103                                        bool has_ownership, void* data)
104     : GlBuffer(target, id, bytes_size, offset, has_ownership), data_(data) {}
105 
GlPersistentBuffer()106 GlPersistentBuffer::GlPersistentBuffer()
107     : GlPersistentBuffer(GL_INVALID_ENUM, GL_INVALID_INDEX, 0, 0, false,
108                          nullptr) {}
109 
GlPersistentBuffer(GlPersistentBuffer && buffer)110 GlPersistentBuffer::GlPersistentBuffer(GlPersistentBuffer&& buffer)
111     : GlBuffer(std::move(buffer)), data_(buffer.data_) {}
112 
operator =(GlPersistentBuffer && buffer)113 GlPersistentBuffer& GlPersistentBuffer::operator=(GlPersistentBuffer&& buffer) {
114   if (this != &buffer) {
115     data_ = buffer.data_;
116     GlBuffer::operator=(std::move(buffer));
117   }
118   return *this;
119 }
120 
~GlPersistentBuffer()121 GlPersistentBuffer::~GlPersistentBuffer() {
122   if (!data_) return;
123   gl_buffer_internal::BufferBinder binder(GL_SHADER_STORAGE_BUFFER, id());
124   glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
125 }
126 
CreatePersistentBuffer(size_t size,GlPersistentBuffer * gl_buffer)127 absl::Status CreatePersistentBuffer(size_t size,
128                                     GlPersistentBuffer* gl_buffer) {
129   PFNGLBUFFERSTORAGEEXTPROC glBufferStorageEXT = nullptr;
130   glBufferStorageEXT = reinterpret_cast<PFNGLBUFFERSTORAGEEXTPROC>(
131       eglGetProcAddress("glBufferStorageEXT"));
132   if (!glBufferStorageEXT) {
133     return absl::UnavailableError("glBufferStorageEXT is not supported");
134   }
135   gl_buffer_internal::BufferId id;
136   gl_buffer_internal::BufferBinder binder(GL_SHADER_STORAGE_BUFFER, id.id());
137   RETURN_IF_ERROR(TFLITE_GPU_CALL_GL(
138       glBufferStorageEXT, GL_SHADER_STORAGE_BUFFER, size, nullptr,
139       GL_MAP_COHERENT_BIT_EXT | GL_MAP_READ_BIT | GL_MAP_WRITE_BIT |
140           GL_MAP_PERSISTENT_BIT_EXT));
141   void* data = nullptr;
142   RETURN_IF_ERROR(TFLITE_GPU_CALL_GL(
143       glMapBufferRange, &data, GL_SHADER_STORAGE_BUFFER, 0, size,
144       GL_MAP_READ_BIT | GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT_EXT));
145   *gl_buffer = GlPersistentBuffer{
146       GL_SHADER_STORAGE_BUFFER, id.Release(), size, 0, true, data};
147   return absl::OkStatus();
148 }
149 
150 namespace gl_buffer_internal {
151 
BufferMapper(GLenum target,size_t offset,size_t bytes,GLbitfield access)152 BufferMapper::BufferMapper(GLenum target, size_t offset, size_t bytes,
153                            GLbitfield access)
154     : target_(target),
155       data_(glMapBufferRange(target_, offset, bytes, access)) {}
156 
~BufferMapper()157 BufferMapper::~BufferMapper() {
158   TFLITE_GPU_CALL_GL(glUnmapBuffer, target_).IgnoreError();
159 }
160 
161 };  // namespace gl_buffer_internal
162 
163 }  // namespace gl
164 }  // namespace gpu
165 }  // namespace tflite
166