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