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_texture.h"
17
18 #include "tensorflow/lite/delegates/gpu/common/data_type.h"
19 #include "tensorflow/lite/delegates/gpu/common/status.h"
20 #include "tensorflow/lite/delegates/gpu/common/types.h"
21 #include "tensorflow/lite/delegates/gpu/gl/gl_call.h"
22 #include "tensorflow/lite/delegates/gpu/gl/gl_errors.h"
23 #include "tensorflow/lite/delegates/gpu/gl/gl_texture_helper.h"
24
25 namespace tflite {
26 namespace gpu {
27 namespace gl {
28
GlTexture(GlTexture && texture)29 GlTexture::GlTexture(GlTexture&& texture)
30 : GlTexture(texture.target_, texture.id_, texture.format_,
31 texture.bytes_size_, texture.layer_, texture.owned_) {
32 texture.owned_ = false;
33 }
34
operator =(GlTexture && texture)35 GlTexture& GlTexture::operator=(GlTexture&& texture) {
36 if (this != &texture) {
37 Invalidate();
38
39 target_ = texture.target_;
40 format_ = texture.format_;
41 bytes_size_ = texture.bytes_size_;
42 layer_ = texture.layer_;
43 owned_ = texture.owned_;
44 id_ = texture.id_;
45 texture.owned_ = false;
46 }
47 return *this;
48 }
49
~GlTexture()50 GlTexture::~GlTexture() {
51 Invalidate();
52 }
53
Invalidate()54 void GlTexture::Invalidate() {
55 if (owned_ && id_ != GL_INVALID_INDEX) {
56 TFLITE_GPU_CALL_GL(glDeleteTextures, 1, &id_).IgnoreError();
57 id_ = GL_INVALID_INDEX;
58 }
59 }
60
BindImage(uint32_t index,GLenum access) const61 absl::Status GlTexture::BindImage(uint32_t index, GLenum access) const {
62 return TFLITE_GPU_CALL_GL(glBindImageTexture, index, id_, /* level = */ 0,
63 /* layered = */ GL_TRUE, layer_, access, format_);
64 }
65
BindAsReadonlyImage(uint32_t index) const66 absl::Status GlTexture::BindAsReadonlyImage(uint32_t index) const {
67 return BindImage(index, GL_READ_ONLY);
68 }
69
BindAsWriteonlyImage(uint32_t index) const70 absl::Status GlTexture::BindAsWriteonlyImage(uint32_t index) const {
71 return BindImage(index, GL_WRITE_ONLY);
72 }
73
BindAsReadWriteImage(uint32_t index) const74 absl::Status GlTexture::BindAsReadWriteImage(uint32_t index) const {
75 return BindImage(index, GL_READ_WRITE);
76 }
77
BindAsSampler2D(uint32_t index) const78 absl::Status GlTexture::BindAsSampler2D(uint32_t index) const {
79 RETURN_IF_ERROR(TFLITE_GPU_CALL_GL(glActiveTexture, GL_TEXTURE0 + index));
80 return TFLITE_GPU_CALL_GL(glBindTexture, GL_TEXTURE_2D, id_);
81 }
82
83 namespace {
84
SetTextureWrapAndFilter(GLenum target,GLenum texture_format)85 absl::Status SetTextureWrapAndFilter(GLenum target, GLenum texture_format) {
86 if (texture_format == GL_RGBA32F) {
87 RETURN_IF_ERROR(TFLITE_GPU_CALL_GL(glTexParameteri, target,
88 GL_TEXTURE_WRAP_S, GL_REPEAT));
89 RETURN_IF_ERROR(TFLITE_GPU_CALL_GL(glTexParameteri, target,
90 GL_TEXTURE_WRAP_T, GL_REPEAT));
91 if (target == GL_TEXTURE_2D_ARRAY || target == GL_TEXTURE_3D) {
92 RETURN_IF_ERROR(TFLITE_GPU_CALL_GL(glTexParameteri, target,
93 GL_TEXTURE_WRAP_R, GL_REPEAT));
94 }
95 // Texture filtering is not available for GL_RGBA32F, hence explicitly
96 // specifying GL_NEAREST param for texture (Otherwise, we can end up
97 // sampling some incorrect values from texture.)
98 RETURN_IF_ERROR(TFLITE_GPU_CALL_GL(glTexParameteri, target,
99 GL_TEXTURE_MAG_FILTER, GL_NEAREST));
100 RETURN_IF_ERROR(TFLITE_GPU_CALL_GL(glTexParameteri, target,
101 GL_TEXTURE_MIN_FILTER, GL_NEAREST));
102 } else if (texture_format == GL_RGBA16F) {
103 RETURN_IF_ERROR(TFLITE_GPU_CALL_GL(glTexParameteri, target,
104 GL_TEXTURE_WRAP_S, GL_REPEAT));
105 RETURN_IF_ERROR(TFLITE_GPU_CALL_GL(glTexParameteri, target,
106 GL_TEXTURE_WRAP_T, GL_REPEAT));
107 if (target == GL_TEXTURE_2D_ARRAY || target == GL_TEXTURE_3D) {
108 RETURN_IF_ERROR(TFLITE_GPU_CALL_GL(glTexParameteri, target,
109 GL_TEXTURE_WRAP_R, GL_REPEAT));
110 }
111 // Texture filtering is available for GL_RGBA16F, specifying that
112 // explicitly improves quality for some operations like texture upscaling
113 RETURN_IF_ERROR(TFLITE_GPU_CALL_GL(glTexParameteri, target,
114 GL_TEXTURE_MAG_FILTER, GL_LINEAR));
115 RETURN_IF_ERROR(TFLITE_GPU_CALL_GL(glTexParameteri, target,
116 GL_TEXTURE_MIN_FILTER, GL_LINEAR));
117 }
118 return absl::OkStatus();
119 }
120
CreateReadOnlyRgba2dImageTexture(DataType data_type,const uint2 & size,const void * data,size_t byte_size,GlTexture * gl_texture)121 absl::Status CreateReadOnlyRgba2dImageTexture(DataType data_type,
122 const uint2& size,
123 const void* data,
124 size_t byte_size,
125 GlTexture* gl_texture) {
126 if (byte_size != /* RGBA=*/4 * SizeOf(data_type) * size.x * size.y) {
127 return absl::InvalidArgumentError(
128 "Creating image texture failed. Source data size is not matching "
129 "expected dimensions.");
130 }
131 const GLenum kTarget = GL_TEXTURE_2D;
132 GLenum internal_format = ToTextureInternalFormat(data_type);
133 GLenum format = ToTextureFormat(data_type);
134 GLenum type = ToTextureDataType(data_type);
135 gl_texture_internal::TextureId id;
136 gl_texture_internal::TextureBinder binder(kTarget, id.id());
137 RETURN_IF_ERROR(SetTextureWrapAndFilter(kTarget, internal_format));
138 RETURN_IF_ERROR(TFLITE_GPU_CALL_GL(glTexStorage2D, kTarget,
139 /* num_levels = */ 1, internal_format,
140 size.x, size.y));
141 RETURN_IF_ERROR(TFLITE_GPU_CALL_GL(glTexSubImage2D, kTarget, /* level = */ 0,
142 0, 0, size.x, size.y, format, type, data));
143 *gl_texture = GlTexture(kTarget, id.Release(), internal_format, byte_size, 0,
144 /*owned=*/true);
145 return absl::OkStatus();
146 }
147
CreateReadOnlyRgba3dImageTexture(DataType data_type,const uint3 & size,const void * data,size_t byte_size,GlTexture * gl_texture)148 absl::Status CreateReadOnlyRgba3dImageTexture(DataType data_type,
149 const uint3& size,
150 const void* data,
151 size_t byte_size,
152 GlTexture* gl_texture) {
153 if (byte_size != /* RGBA=*/4 * SizeOf(data_type) * size.x * size.y * size.z) {
154 return absl::InvalidArgumentError(
155 "Creating image texture failed. Source data is larger than dimensions "
156 "product.");
157 }
158 const GLenum kTarget = GL_TEXTURE_2D_ARRAY;
159 GLenum internal_format = ToTextureInternalFormat(data_type);
160 GLenum format = ToTextureFormat(data_type);
161 GLenum type = ToTextureDataType(data_type);
162 gl_texture_internal::TextureId id;
163 gl_texture_internal::TextureBinder binder(kTarget, id.id());
164 RETURN_IF_ERROR(SetTextureWrapAndFilter(kTarget, internal_format));
165 RETURN_IF_ERROR(TFLITE_GPU_CALL_GL(glTexStorage3D, kTarget,
166 /* num_levels = */ 1, internal_format,
167 size.x, size.y, size.z));
168 RETURN_IF_ERROR(TFLITE_GPU_CALL_GL(glTexSubImage3D, kTarget, /* level = */ 0,
169 0, 0, 0, size.x, size.y, size.z, format,
170 type, data));
171 *gl_texture = GlTexture(kTarget, id.Release(), internal_format, byte_size, 0,
172 /*owned=*/true);
173 return absl::OkStatus();
174 }
175
176 } // namespace
177
CreateReadOnlyImageTexture(const uint2 & size,absl::Span<const float> data,GlTexture * gl_texture)178 absl::Status CreateReadOnlyImageTexture(const uint2& size,
179 absl::Span<const float> data,
180 GlTexture* gl_texture) {
181 return CreateReadOnlyRgba2dImageTexture(DataType::FLOAT32, size, data.data(),
182 data.size() * sizeof(float),
183 gl_texture);
184 }
185
CreateReadOnlyImageTexture(const uint3 & size,absl::Span<const float> data,GlTexture * gl_texture)186 absl::Status CreateReadOnlyImageTexture(const uint3& size,
187 absl::Span<const float> data,
188 GlTexture* gl_texture) {
189 return CreateReadOnlyRgba3dImageTexture(DataType::FLOAT32, size, data.data(),
190 data.size() * sizeof(float),
191 gl_texture);
192 }
193
CreateReadOnlyImageTextureU8(const uint2 & size,absl::Span<const uint8_t> data,GlTexture * gl_texture)194 absl::Status CreateReadOnlyImageTextureU8(const uint2& size,
195 absl::Span<const uint8_t> data,
196 GlTexture* gl_texture) {
197 return CreateReadOnlyRgba2dImageTexture(DataType::UINT8, size, data.data(),
198 data.size() * sizeof(uint8_t),
199 gl_texture);
200 }
201
CreateReadOnlyImageTextureF16(const uint2 & size,absl::Span<const uint16_t> data,GlTexture * gl_texture)202 absl::Status CreateReadOnlyImageTextureF16(const uint2& size,
203 absl::Span<const uint16_t> data,
204 GlTexture* gl_texture) {
205 return CreateReadOnlyRgba2dImageTexture(DataType::FLOAT16, size, data.data(),
206 data.size() * sizeof(uint16_t),
207 gl_texture);
208 }
209
CreateReadOnlyImageTextureF16(const uint3 & size,absl::Span<const uint16_t> data,GlTexture * gl_texture)210 absl::Status CreateReadOnlyImageTextureF16(const uint3& size,
211 absl::Span<const uint16_t> data,
212 GlTexture* gl_texture) {
213 return CreateReadOnlyRgba3dImageTexture(DataType::FLOAT16, size, data.data(),
214 data.size() * sizeof(uint16_t),
215 gl_texture);
216 }
217
CreateReadWriteRgbaImageTexture(DataType data_type,const uint2 & size,GlTexture * gl_texture)218 absl::Status CreateReadWriteRgbaImageTexture(DataType data_type,
219 const uint2& size,
220 GlTexture* gl_texture) {
221 const GLenum kTarget = GL_TEXTURE_2D;
222 const GLenum internal_format = ToTextureInternalFormat(data_type);
223 gl_texture_internal::TextureId id;
224 gl_texture_internal::TextureBinder binder(kTarget, id.id());
225 RETURN_IF_ERROR(SetTextureWrapAndFilter(kTarget, internal_format));
226 RETURN_IF_ERROR(TFLITE_GPU_CALL_GL(glTexStorage2D, kTarget,
227 /* num_levels = */ 1, internal_format,
228 size.x, size.y));
229 size_t byte_size = /* RGBA = */ 4 * SizeOf(data_type) * size.x * size.y;
230 *gl_texture = GlTexture(kTarget, id.Release(), internal_format, byte_size,
231 /* layer = */ 0,
232 /* owned = */ true);
233 return absl::OkStatus();
234 }
235
CreateReadWriteRgbaImageTexture(DataType data_type,const uint3 & size,GlTexture * gl_texture)236 absl::Status CreateReadWriteRgbaImageTexture(DataType data_type,
237 const uint3& size,
238 GlTexture* gl_texture) {
239 const GLenum kTarget = GL_TEXTURE_2D_ARRAY;
240 GLenum internal_format = ToTextureInternalFormat(data_type);
241 gl_texture_internal::TextureId id;
242 gl_texture_internal::TextureBinder binder(kTarget, id.id());
243 RETURN_IF_ERROR(SetTextureWrapAndFilter(kTarget, internal_format));
244 RETURN_IF_ERROR(TFLITE_GPU_CALL_GL(glTexStorage3D, kTarget,
245 /* num_levels = */ 1, internal_format,
246 size.x, size.y, size.z));
247 size_t byte_size =
248 /* RGBA = */ 4 * SizeOf(data_type) * size.x * size.y * size.z;
249 *gl_texture = GlTexture(kTarget, id.Release(), internal_format, byte_size,
250 /* layer = */ 0,
251 /* owned = */ true);
252 return absl::OkStatus();
253 }
254
255 } // namespace gl
256 } // namespace gpu
257 } // namespace tflite
258