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