• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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