xref: /aosp_15_r20/external/tensorflow/tensorflow/lite/delegates/gpu/gl/gl_texture.cc (revision b6fb3261f9314811a0f4371741dbb8839866f948)
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   const bool normalized = data_type == DataType::UINT8;
133   GLenum internal_format = ToTextureInternalFormat(data_type, normalized);
134   GLenum format = ToTextureFormat(data_type, normalized);
135   GLenum type = ToTextureDataType(data_type);
136   gl_texture_internal::TextureId id;
137   gl_texture_internal::TextureBinder binder(kTarget, id.id());
138   RETURN_IF_ERROR(SetTextureWrapAndFilter(kTarget, internal_format));
139   RETURN_IF_ERROR(TFLITE_GPU_CALL_GL(glTexStorage2D, kTarget,
140                                      /* num_levels = */ 1, internal_format,
141                                      size.x, size.y));
142   RETURN_IF_ERROR(TFLITE_GPU_CALL_GL(glTexSubImage2D, kTarget, /* level = */ 0,
143                                      0, 0, size.x, size.y, format, type, data));
144   *gl_texture = GlTexture(kTarget, id.Release(), internal_format, byte_size, 0,
145                           /*owned=*/true);
146   return absl::OkStatus();
147 }
148 
CreateReadOnlyRgba3dImageTexture(DataType data_type,const uint3 & size,const void * data,size_t byte_size,GlTexture * gl_texture)149 absl::Status CreateReadOnlyRgba3dImageTexture(DataType data_type,
150                                               const uint3& size,
151                                               const void* data,
152                                               size_t byte_size,
153                                               GlTexture* gl_texture) {
154   if (byte_size != /* RGBA=*/4 * SizeOf(data_type) * size.x * size.y * size.z) {
155     return absl::InvalidArgumentError(
156         "Creating image texture failed. Source data is larger than dimensions "
157         "product.");
158   }
159   const GLenum kTarget = GL_TEXTURE_2D_ARRAY;
160   const bool normalized = data_type == DataType::UINT8;
161   GLenum internal_format = ToTextureInternalFormat(data_type, normalized);
162   GLenum format = ToTextureFormat(data_type, normalized);
163   GLenum type = ToTextureDataType(data_type);
164   gl_texture_internal::TextureId id;
165   gl_texture_internal::TextureBinder binder(kTarget, id.id());
166   RETURN_IF_ERROR(SetTextureWrapAndFilter(kTarget, internal_format));
167   RETURN_IF_ERROR(TFLITE_GPU_CALL_GL(glTexStorage3D, kTarget,
168                                      /* num_levels = */ 1, internal_format,
169                                      size.x, size.y, size.z));
170   RETURN_IF_ERROR(TFLITE_GPU_CALL_GL(glTexSubImage3D, kTarget, /* level = */ 0,
171                                      0, 0, 0, size.x, size.y, size.z, format,
172                                      type, data));
173   *gl_texture = GlTexture(kTarget, id.Release(), internal_format, byte_size, 0,
174                           /*owned=*/true);
175   return absl::OkStatus();
176 }
177 
178 }  // namespace
179 
CreateReadOnlyImageTexture(const uint2 & size,absl::Span<const float> data,GlTexture * gl_texture)180 absl::Status CreateReadOnlyImageTexture(const uint2& size,
181                                         absl::Span<const float> data,
182                                         GlTexture* gl_texture) {
183   return CreateReadOnlyRgba2dImageTexture(DataType::FLOAT32, size, data.data(),
184                                           data.size() * sizeof(float),
185                                           gl_texture);
186 }
187 
CreateReadOnlyImageTexture(const uint3 & size,absl::Span<const float> data,GlTexture * gl_texture)188 absl::Status CreateReadOnlyImageTexture(const uint3& size,
189                                         absl::Span<const float> data,
190                                         GlTexture* gl_texture) {
191   return CreateReadOnlyRgba3dImageTexture(DataType::FLOAT32, size, data.data(),
192                                           data.size() * sizeof(float),
193                                           gl_texture);
194 }
195 
CreateReadOnlyImageTextureU8(const uint2 & size,absl::Span<const uint8_t> data,GlTexture * gl_texture)196 absl::Status CreateReadOnlyImageTextureU8(const uint2& size,
197                                           absl::Span<const uint8_t> data,
198                                           GlTexture* gl_texture) {
199   return CreateReadOnlyRgba2dImageTexture(DataType::UINT8, size, data.data(),
200                                           data.size() * sizeof(uint8_t),
201                                           gl_texture);
202 }
203 
CreateReadOnlyImageTextureF16(const uint2 & size,absl::Span<const uint16_t> data,GlTexture * gl_texture)204 absl::Status CreateReadOnlyImageTextureF16(const uint2& size,
205                                            absl::Span<const uint16_t> data,
206                                            GlTexture* gl_texture) {
207   return CreateReadOnlyRgba2dImageTexture(DataType::FLOAT16, size, data.data(),
208                                           data.size() * sizeof(uint16_t),
209                                           gl_texture);
210 }
211 
CreateReadOnlyImageTextureF16(const uint3 & size,absl::Span<const uint16_t> data,GlTexture * gl_texture)212 absl::Status CreateReadOnlyImageTextureF16(const uint3& size,
213                                            absl::Span<const uint16_t> data,
214                                            GlTexture* gl_texture) {
215   return CreateReadOnlyRgba3dImageTexture(DataType::FLOAT16, size, data.data(),
216                                           data.size() * sizeof(uint16_t),
217                                           gl_texture);
218 }
219 
CreateReadWriteRgbaImageTexture(DataType data_type,const uint2 & size,GlTexture * gl_texture)220 absl::Status CreateReadWriteRgbaImageTexture(DataType data_type,
221                                              const uint2& size,
222                                              GlTexture* gl_texture) {
223   const GLenum kTarget = GL_TEXTURE_2D;
224   const bool normalized = data_type == DataType::UINT8;
225   const GLenum internal_format = ToTextureInternalFormat(data_type, normalized);
226   gl_texture_internal::TextureId id;
227   gl_texture_internal::TextureBinder binder(kTarget, id.id());
228   RETURN_IF_ERROR(SetTextureWrapAndFilter(kTarget, internal_format));
229   RETURN_IF_ERROR(TFLITE_GPU_CALL_GL(glTexStorage2D, kTarget,
230                                      /* num_levels = */ 1, internal_format,
231                                      size.x, size.y));
232   size_t byte_size = /* RGBA = */ 4 * SizeOf(data_type) * size.x * size.y;
233   *gl_texture = GlTexture(kTarget, id.Release(), internal_format, byte_size,
234                           /* layer = */ 0,
235                           /* owned = */ true);
236   return absl::OkStatus();
237 }
238 
CreateReadWriteRgbaImageTexture(DataType data_type,const uint3 & size,GlTexture * gl_texture)239 absl::Status CreateReadWriteRgbaImageTexture(DataType data_type,
240                                              const uint3& size,
241                                              GlTexture* gl_texture) {
242   const GLenum kTarget = GL_TEXTURE_2D_ARRAY;
243   const bool normalized = data_type == DataType::UINT8;
244   GLenum internal_format = ToTextureInternalFormat(data_type, normalized);
245   gl_texture_internal::TextureId id;
246   gl_texture_internal::TextureBinder binder(kTarget, id.id());
247   RETURN_IF_ERROR(SetTextureWrapAndFilter(kTarget, internal_format));
248   RETURN_IF_ERROR(TFLITE_GPU_CALL_GL(glTexStorage3D, kTarget,
249                                      /* num_levels = */ 1, internal_format,
250                                      size.x, size.y, size.z));
251   size_t byte_size =
252       /* RGBA = */ 4 * SizeOf(data_type) * size.x * size.y * size.z;
253   *gl_texture = GlTexture(kTarget, id.Release(), internal_format, byte_size,
254                           /* layer = */ 0,
255                           /* owned = */ true);
256   return absl::OkStatus();
257 }
258 
259 }  // namespace gl
260 }  // namespace gpu
261 }  // namespace tflite
262