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