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