Internal change.
PiperOrigin-RevId: 493973435
This commit is contained in:
		
							parent
							
								
									a641ea12e1
								
							
						
					
					
						commit
						0fbaa8dc8a
					
				
							
								
								
									
										143
									
								
								mediapipe/framework/formats/tensor_ahwb_gpu_test.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										143
									
								
								mediapipe/framework/formats/tensor_ahwb_gpu_test.cc
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,143 @@ | |||
| 
 | ||||
| #if !defined(MEDIAPIPE_NO_JNI) && \ | ||||
|     (__ANDROID_API__ >= 26 ||     \ | ||||
|      defined(__ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__)) | ||||
| #include <android/hardware_buffer.h> | ||||
| 
 | ||||
| #include <cstdint> | ||||
| 
 | ||||
| #include "mediapipe/framework/formats/tensor.h" | ||||
| #include "mediapipe/framework/formats/tensor_data_types.h" | ||||
| #include "mediapipe/gpu/gpu_test_base.h" | ||||
| #include "mediapipe/gpu/shader_util.h" | ||||
| #include "tensorflow/lite/delegates/gpu/gl/gl_call.h" | ||||
| #include "testing/base/public/gunit.h" | ||||
| 
 | ||||
| // The test creates OpenGL ES buffer, fills the buffer with incrementing values
 | ||||
| // 0.0, 0.1, 0.2 etc. with the compute shader on GPU.
 | ||||
| // Then the test requests the CPU view and compares the values.
 | ||||
| // Float32 and Float16 tests are there.
 | ||||
| 
 | ||||
| namespace { | ||||
| 
 | ||||
| using mediapipe::Float16; | ||||
| using mediapipe::Tensor; | ||||
| 
 | ||||
| MATCHER_P(NearWithPrecision, precision, "") { | ||||
|   return std::abs(std::get<0>(arg) - std::get<1>(arg)) < precision; | ||||
| } | ||||
| 
 | ||||
| #if MEDIAPIPE_OPENGL_ES_VERSION >= MEDIAPIPE_OPENGL_ES_31 | ||||
| 
 | ||||
| // Utility function to fill the GPU buffer.
 | ||||
| void FillGpuBuffer(GLuint name, std::size_t size, | ||||
|                    const Tensor::ElementType fmt) { | ||||
|   std::string shader_source; | ||||
|   if (fmt == Tensor::ElementType::kFloat32) { | ||||
|     shader_source = R"( #version 310 es | ||||
|     precision highp float; | ||||
|     layout(local_size_x = 1, local_size_y = 1) in; | ||||
|     layout(std430, binding = 0) buffer Output {float elements[];} output_data; | ||||
|     void main() { | ||||
|       uint v = gl_GlobalInvocationID.x * 2u; | ||||
|       output_data.elements[v] = float(v) / 10.0; | ||||
|       output_data.elements[v + 1u] = float(v + 1u) / 10.0; | ||||
|     })"; | ||||
|   } else { | ||||
|     shader_source = R"( #version 310 es | ||||
|       precision highp float; | ||||
|       layout(local_size_x = 1, local_size_y = 1) in; | ||||
|       layout(std430, binding = 0) buffer Output {float elements[];} output_data; | ||||
|       void main() { | ||||
|         uint v = gl_GlobalInvocationID.x; | ||||
|         uint tmp = packHalf2x16(vec2((float(v)* 2.0 + 0.0) / 10.0, | ||||
|                                      (float(v) * 2.0 + 1.0) / 10.0)); | ||||
|         output_data.elements[v] = uintBitsToFloat(tmp); | ||||
|       })"; | ||||
|   } | ||||
|   GLuint shader; | ||||
|   MP_ASSERT_OK(TFLITE_GPU_CALL_GL(glCreateShader, &shader, GL_COMPUTE_SHADER)); | ||||
|   const GLchar* sources[] = {shader_source.c_str()}; | ||||
|   MP_ASSERT_OK(TFLITE_GPU_CALL_GL(glShaderSource, shader, 1, sources, nullptr)); | ||||
|   MP_ASSERT_OK(TFLITE_GPU_CALL_GL(glCompileShader, shader)); | ||||
|   GLint is_compiled = 0; | ||||
|   MP_ASSERT_OK(TFLITE_GPU_CALL_GL(glGetShaderiv, shader, GL_COMPILE_STATUS, | ||||
|                                   &is_compiled)); | ||||
|   if (is_compiled == GL_FALSE) { | ||||
|     GLint max_length = 0; | ||||
|     MP_ASSERT_OK(TFLITE_GPU_CALL_GL(glGetShaderiv, shader, GL_INFO_LOG_LENGTH, | ||||
|                                     &max_length)); | ||||
|     std::vector<GLchar> error_log(max_length); | ||||
|     glGetShaderInfoLog(shader, max_length, &max_length, error_log.data()); | ||||
|     glDeleteShader(shader); | ||||
|     FAIL() << error_log.data(); | ||||
|     return; | ||||
|   } | ||||
|   GLuint to_buffer_program; | ||||
|   MP_ASSERT_OK(TFLITE_GPU_CALL_GL(glCreateProgram, &to_buffer_program)); | ||||
|   MP_ASSERT_OK(TFLITE_GPU_CALL_GL(glAttachShader, to_buffer_program, shader)); | ||||
|   MP_ASSERT_OK(TFLITE_GPU_CALL_GL(glDeleteShader, shader)); | ||||
|   MP_ASSERT_OK(TFLITE_GPU_CALL_GL(glLinkProgram, to_buffer_program)); | ||||
| 
 | ||||
|   MP_ASSERT_OK( | ||||
|       TFLITE_GPU_CALL_GL(glBindBufferBase, GL_SHADER_STORAGE_BUFFER, 0, name)); | ||||
|   MP_ASSERT_OK(TFLITE_GPU_CALL_GL(glUseProgram, to_buffer_program)); | ||||
|   MP_ASSERT_OK(TFLITE_GPU_CALL_GL(glDispatchCompute, size / 2, 1, 1)); | ||||
|   MP_ASSERT_OK(TFLITE_GPU_CALL_GL(glBindBuffer, GL_SHADER_STORAGE_BUFFER, 0)); | ||||
|   MP_ASSERT_OK(TFLITE_GPU_CALL_GL(glDeleteProgram, to_buffer_program)); | ||||
| } | ||||
| 
 | ||||
| class TensorAhwbGpuTest : public mediapipe::GpuTestBase { | ||||
|  public: | ||||
| }; | ||||
| 
 | ||||
| TEST_F(TensorAhwbGpuTest, TestGpuToCpuFloat32) { | ||||
|   Tensor::SetPreferredStorageType(Tensor::StorageType::kAhwb); | ||||
|   constexpr size_t num_elements = 20; | ||||
|   Tensor tensor{Tensor::ElementType::kFloat32, Tensor::Shape({num_elements})}; | ||||
|   RunInGlContext([&tensor] { | ||||
|     auto ssbo_view = tensor.GetOpenGlBufferWriteView(); | ||||
|     auto ssbo_name = ssbo_view.name(); | ||||
|     EXPECT_GT(ssbo_name, 0); | ||||
|     FillGpuBuffer(ssbo_name, tensor.shape().num_elements(), | ||||
|                   tensor.element_type()); | ||||
|   }); | ||||
|   auto ptr = tensor.GetCpuReadView().buffer<float>(); | ||||
|   EXPECT_NE(ptr, nullptr); | ||||
|   std::vector<float> reference; | ||||
|   reference.resize(num_elements); | ||||
|   for (int i = 0; i < num_elements; i++) { | ||||
|     reference[i] = static_cast<float>(i) / 10.0f; | ||||
|   } | ||||
|   EXPECT_THAT(absl::Span<const float>(ptr, num_elements), | ||||
|               testing::Pointwise(testing::FloatEq(), reference)); | ||||
| } | ||||
| 
 | ||||
| TEST_F(TensorAhwbGpuTest, TestGpuToCpuFloat16) { | ||||
|   Tensor::SetPreferredStorageType(Tensor::StorageType::kAhwb); | ||||
|   constexpr size_t num_elements = 20; | ||||
|   Tensor tensor{Tensor::ElementType::kFloat16, Tensor::Shape({num_elements})}; | ||||
|   RunInGlContext([&tensor] { | ||||
|     auto ssbo_view = tensor.GetOpenGlBufferWriteView(); | ||||
|     auto ssbo_name = ssbo_view.name(); | ||||
|     EXPECT_GT(ssbo_name, 0); | ||||
|     FillGpuBuffer(ssbo_name, tensor.shape().num_elements(), | ||||
|                   tensor.element_type()); | ||||
|   }); | ||||
|   auto ptr = tensor.GetCpuReadView().buffer<Float16>(); | ||||
|   EXPECT_NE(ptr, nullptr); | ||||
|   std::vector<Float16> reference; | ||||
|   reference.resize(num_elements); | ||||
|   for (int i = 0; i < num_elements; i++) { | ||||
|     reference[i] = static_cast<float>(i) / 10.0f; | ||||
|   } | ||||
|   // Precision is set to a reasonable value for Float16.
 | ||||
|   EXPECT_THAT(absl::Span<const Float16>(ptr, num_elements), | ||||
|               testing::Pointwise(NearWithPrecision(0.001), reference)); | ||||
| } | ||||
| 
 | ||||
| #endif  // MEDIAPIPE_OPENGL_ES_VERSION >= MEDIAPIPE_OPENGL_ES_31
 | ||||
| }  // namespace
 | ||||
| 
 | ||||
| #endif  // !defined(MEDIAPIPE_NO_JNI) && (__ANDROID_API__ >= 26 ||
 | ||||
|         // defined(__ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__))
 | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user