add visualizer support for debug and test
authorInki Dae <inki.dae@samsung.com>
Fri, 15 Mar 2024 08:25:33 +0000 (17:25 +0900)
committerInki Dae <inki.dae@samsung.com>
Tue, 26 Mar 2024 03:43:32 +0000 (12:43 +0900)
Add visualizer support to display service result on the screen
through Native window system.

The visualizer will be used only for debug and test.

With this patch, test_autozoom_on_screen binary will be created,
And this binary will display the service result on the screen.

Signed-off-by: Inki Dae <inki.dae@samsung.com>
24 files changed:
CMakeLists.txt
capi/singleo_native_capi_internal.h [new file with mode: 0644]
packaging/singleo.spec
services/auto_zoom/include/AutoZoom.h
services/auto_zoom/src/AutoZoom.cpp
services/common/include/IService.h
services/common/include/ImagePreprocessor.h
services/common/src/ImagePreprocessor.cpp
services/singleo_native_capi.cpp
test/CMakeLists.txt
test/services/CMakeLists.txt
test/services/test_autozoom_on_screen.cpp [new file with mode: 0644]
visualizer/CMakeLists.txt [new file with mode: 0644]
visualizer/include/singleo_util_matrix.h [new file with mode: 0644]
visualizer/include/singleo_util_render_2d.h [new file with mode: 0644]
visualizer/include/singleo_util_shader.h [new file with mode: 0644]
visualizer/include/singleo_util_visualizer_2d.h [new file with mode: 0644]
visualizer/include/singleo_util_winsys.h [new file with mode: 0644]
visualizer/singleo_util_visualizer_rd.proto [new file with mode: 0644]
visualizer/src/singleo_util_matrix.cpp [new file with mode: 0644]
visualizer/src/singleo_util_render_2d.cpp [new file with mode: 0644]
visualizer/src/singleo_util_shader.cpp [new file with mode: 0644]
visualizer/src/singleo_util_visualizer_2d.cpp [new file with mode: 0644]
visualizer/src/singleo_util_winsys.cpp [new file with mode: 0644]

index 38941d465079c30c27133797d46f50ff85e044d4..50f7a5275eaa1f99957c4adaf414d1cfda6aea34 100644 (file)
@@ -6,6 +6,7 @@ ADD_SUBDIRECTORY(input)
 ADD_SUBDIRECTORY(inference)
 ADD_SUBDIRECTORY(services)
 ADD_SUBDIRECTORY(test)
+ADD_SUBDIRECTORY(visualizer)
 
 SET(PC_NAME ${PROJECT_NAME})
 SET(PC_LDFLAGS -l${PROJECT_NAME})
diff --git a/capi/singleo_native_capi_internal.h b/capi/singleo_native_capi_internal.h
new file mode 100644 (file)
index 0000000..8439d26
--- /dev/null
@@ -0,0 +1,66 @@
+/**
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef __SINGLEO_NATIVE_CAPI_INTERNAL_H__
+#define __SINGLEO_NATIVE_CAPI_INTERNAL_H__
+
+#include "singleo_native_capi.h"
+
+typedef void (*singleo_user_cb_t)(unsigned char *buffer, unsigned int width, unsigned int height,
+                                                                 unsigned int bytes_per_pixel, void *user_data);
+
+/**
+ * @internal
+ * @brief Registers user-given callback for user to receive result mixed with input data.
+ *
+ * @since_tizen 9.0
+ * @remarks With this function, user can receive result mixed with input data by callback.
+ *          This API is valid only in case of using asynchronous mode.
+ *
+ * @param[in] handle   The handle to the service.
+ *
+ * @return 0 on success, otherwise a negative error value
+ * @retval #SINGLEO_SERVICE_ERROR_NONE Successful
+ * @retval #SINGLEO_SERVICE_ERROR_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #SINGLEO_SERVICE_ERROR_ERROR_INVALID_OPERATION Invalid operation
+ *
+ * @pre Create a source handle by calling singleo_service_create()
+ */
+int singleo_service_register_user_callback(singleo_service_h handle,
+                                                                                  void (*callback_ptr)(unsigned char *buffer, unsigned int width,
+                                                                                                                               unsigned int height, unsigned int bytes_per_pixel,
+                                                                                                                               void *user_data),
+                                                                                  void *user_data);
+
+/**
+ * @internal
+ * @brief Unregisters user-given callback.
+ *
+ * @since_tizen 9.0
+ * @remarks This API unregister the callback registered by user.
+ *
+ * @param[in] handle   The handle to the service.
+ *
+ * @return 0 on success, otherwise a negative error value
+ * @retval #SINGLEO_SERVICE_ERROR_NONE Successful
+ * @retval #SINGLEO_SERVICE_ERROR_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #SINGLEO_SERVICE_ERROR_ERROR_INVALID_OPERATION Invalid operation
+ *
+ * @pre Create a source handle by calling singleo_service_create()
+ * @pre Register a callback by calling singleo_service_register_user_callback()
+ */
+int singleo_service_unregister_user_callback(singleo_service_h handle);
+
+#endif
\ No newline at end of file
index 3d4b2d329165fa380627a2bdc58c8bf755618da4..5b082e976932a62931ca9c4eb19748a5dfdfe376 100644 (file)
@@ -7,9 +7,16 @@ License:     Apache-2.0
 Source0:     %{name}-%{version}.tar.gz
 BuildRequires: cmake
 BuildRequires: pkgconfig(capi-media-vision)
+BuildRequires: pkgconfig(capi-media-tool)
 BuildRequires: pkgconfig(opencv)
 BuildRequires: pkgconfig(dlog)
 BuildRequires: gtest-devel
+BuildRequires: pkgconfig(libdrm)
+BuildRequires: pkgconfig(wayland-egl)
+BuildRequires: pkgconfig(glesv2)
+BuildRequires: pkgconfig(protobuf)
+BuildRequires: pkgconfig(grpc++)
+BuildRequires: pkgconfig(re2)
 
 %define enable_autozoom_api 1
 %define BUILD_OPTIONS -DPLATFORM_IS_TIZEN=0 -DUSE_EXTERNAL_INFERENCE_SERVICE=0 -DUSE_AUTOZOOM_API=%{enable_autozoom_api}
@@ -78,6 +85,8 @@ rm -rf %{buildroot}
 %{_libdir}/libsingleo_service.so
 %{_libdir}/libsingleo_input.so
 %{_libdir}/libsingleo_input_backend.so
+%{_libdir}/libsingleo_visualizer.so
 
 %files test
 %{_bindir}/test_singleo
+%{_bindir}/test_autozoom_on_screen
index d79161936a2a8e3a412562c344defb1297e509a0..8f8cb0cabd911b16d7428ddcf1000186cbcab43f 100644 (file)
@@ -55,9 +55,11 @@ private:
        inference::TaskType _task_type { inference::TaskType::FACE_DETECTION };
 
        bool isKeyValid(std::string key);
-       void updateResult();
+       void updateResult(BaseDataType &input_data);
 
        std::unique_ptr<AsyncManager<ImageDataType, AutoZoomResult> > _async_manager;
+       singleo_user_cb_t _user_cb {};
+       void *_user_data {};
 
 public:
        explicit AutoZoom(input::InputConfigBase &config);
@@ -76,6 +78,8 @@ public:
        void performAsync() override;
        void getResultCnt(unsigned int *cnt) override;
        void getResultInt(unsigned int idx, std::string key, unsigned int *value) override;
+       void registerUserCallback(singleo_user_cb_t user_cb, void *user_data) override;
+       void unregisterUserCallback() override;
 
        std::unique_ptr<AsyncManager<ImageDataType, AutoZoomResult> > &getAsyncManager()
        {
index a2ced5a0acb9c341cde421a0af15d7a3244b895b..16c1288ca92accc2155f06669101eb490ca5f6fa 100644 (file)
@@ -94,7 +94,7 @@ void AutoZoom::perform_with_file(BaseDataType &input_data)
 
        _inference_service->invoke(image_data);
 
-       updateResult();
+       updateResult(preprocessor.getData());
 }
 
 void AutoZoom::perform()
@@ -114,7 +114,7 @@ void AutoZoom::perform()
        preprocessed_image.setData(preprocessor.getData());
        _inference_service->invoke(preprocessed_image);
 
-       updateResult();
+       updateResult(preprocessor.getData());
 }
 
 void AutoZoom::performAsync()
@@ -134,7 +134,7 @@ void AutoZoom::performAsync()
 
                input_container.setData(data);
                auto_zoom->getInferenceService()->invoke(input_container);
-               auto_zoom->updateResult();
+               auto_zoom->updateResult(data);
 
                // This buffer was allocated and copied in inputServiceCb callback.
                // So make sure to release this buffer here.
@@ -144,7 +144,7 @@ void AutoZoom::performAsync()
        });
 }
 
-void AutoZoom::updateResult()
+void AutoZoom::updateResult(BaseDataType &in_data)
 {
        auto &output_data = _inference_service->result();
        unsigned int frame_number = output_data.getFrameNumber();
@@ -165,11 +165,25 @@ void AutoZoom::updateResult()
                }
        }
 
+       // For debug
+       ImagePreprocessor preprocessed_result(in_data);
+
+       // If detected object exists then draw a box on captured image.
+       if (result_cnt > 0)
+               preprocessed_result.drawBox(rect, 0, 0, 255);
+
        // TODO. implement Postprocessor which calculates Autozoom position using above 'result' vector.
 
        SINGLEO_LOGD("result cnt = %zu", result_cnt);
        _result.num_of_result = result_cnt;
 
+       // If user callback exists then call it. This callback is used for the debug.
+       if (_user_cb) {
+               auto imageData = dynamic_cast<ImageDataType &>(preprocessed_result.getData());
+
+               _user_cb(imageData.ptr, imageData.width, imageData.height, imageData.byte_per_pixel, _user_data);
+       }
+
        if (result_cnt == 0) {
                SINGLEO_LOGW("No detected objects.");
                return;
@@ -217,5 +231,17 @@ void AutoZoom::getResultInt(unsigned int idx, std::string key, unsigned int *val
        }
 }
 
+void AutoZoom::registerUserCallback(singleo_user_cb_t user_cb, void *user_data)
+{
+       _user_cb = user_cb;
+       _user_data = user_data;
+}
+
+void AutoZoom::unregisterUserCallback()
+{
+       _user_cb = nullptr;
+       _user_data = nullptr;
+}
+
 }
 }
index ee0c957d941ae9e21703325d17b6731230bdd570..32dc0ce511ba20295bd743819384eb122c8d9c8f 100644 (file)
@@ -17,6 +17,8 @@
 #ifndef __ISERVICE_H__
 #define __ISERVICE_H__
 
+#include "singleo_native_capi_internal.h"
+
 #include "SingleoCommonTypes.h"
 #include "IPreprocessor.h"
 #include "InputDataType.h"
@@ -35,6 +37,8 @@ public:
        virtual void performAsync() = 0;
        virtual void getResultCnt(unsigned int *cnt) = 0;
        virtual void getResultInt(unsigned int idx, std::string key, unsigned int *value) = 0;
+       virtual void registerUserCallback(singleo_user_cb_t user_cb, void *user_data) = 0;
+       virtual void unregisterUserCallback() = 0;
 };
 
 }
index 8591a60307b3519d2b93c07528976f107e7742c7..5473b70d1d3f0e741b0f241a1d9976b092016f4a 100644 (file)
@@ -19,6 +19,7 @@
 
 #include <memory>
 #include <string>
+
 #include <opencv2/opencv.hpp>
 
 #include "IPreprocessor.h"
@@ -45,8 +46,7 @@ public:
        void setData(BaseDataType &data) override;
        BaseDataType &getData() override;
 
-       // For debug
-       void drawRedBox(Rect &rect);
+       void drawBox(Rect &rect, unsigned char r, unsigned char g, unsigned char b);
        void toFile(std::string file_name);
 };
 
index 803029aa49db9dd277df5f8ee1f99686e302c2f2..1021c8a7ecc6bc21af1e0c4fee4101ff5eccbaa1 100644 (file)
@@ -78,12 +78,12 @@ BaseDataType &ImagePreprocessor::getData()
        return _image_data;
 }
 
-void ImagePreprocessor::drawRedBox(Rect &rect)
+void ImagePreprocessor::drawBox(Rect &rect, unsigned char r, unsigned char g, unsigned char b)
 {
        cv::Point leftTop(rect.left, rect.top);
        cv::Point rightBottom(rect.right, rect.bottom);
 
-       cv::rectangle(_cv_image, cv::Rect(leftTop, rightBottom), cv::Scalar(0, 0, 255));
+       cv::rectangle(_cv_image, cv::Rect(leftTop, rightBottom), cv::Scalar(r, g, b));
 }
 
 void ImagePreprocessor::toFile(string file_name)
index e92b8f9acdc2dafc3df168f31103d96e2e7fe2e9..e161af0e57ceb6686b31edfb3156440a3d06f407 100644 (file)
@@ -1,6 +1,6 @@
 #include <dlfcn.h>
 
-#include "singleo_native_capi.h"
+#include "singleo_native_capi_internal.h"
 #include "SingleoException.h"
 #include "Context.h"
 #include "ServiceConfigParser.h"
@@ -120,3 +120,27 @@ int singleo_service_get_result_int(singleo_service_h handle, unsigned int idx, c
 
        return SINGLEO_ERROR_NONE;
 }
+
+int singleo_service_register_user_callback(singleo_service_h handle, singleo_user_cb_t user_cb, void *user_data)
+{
+       try {
+               auto context = static_cast<Context *>(handle);
+               context->_service_handle->registerUserCallback(user_cb, user_data);
+       } catch (const BaseException &e) {
+               return e.getError();
+       }
+
+       return SINGLEO_ERROR_NONE;
+}
+
+int singleo_service_unregister_user_callback(singleo_service_h handle)
+{
+       try {
+               auto context = static_cast<Context *>(handle);
+               context->_service_handle->unregisterUserCallback();
+       } catch (const BaseException &e) {
+               return e.getError();
+       }
+
+       return SINGLEO_ERROR_NONE;
+}
\ No newline at end of file
index fae5c3ddd0b8056e010d61057faf2785659efbc6..f5716b6750b282015d93acf5b37b5c05475f5072 100644 (file)
@@ -1 +1 @@
-add_subdirectory(services)
\ No newline at end of file
+add_subdirectory(services)
index 37ab88e12fc0fb05c4575efab11b0134290f4866..d0b54562499b9a9ba4149206205637fdf19d2578 100644 (file)
@@ -16,4 +16,14 @@ TARGET_INCLUDE_DIRECTORIES(${PROJECT_NAME} PRIVATE ../../capi/ ../../common/incl
 TARGET_LINK_LIBRARIES(${PROJECT_NAME}
     gtest gtest_main pthread singleo_service)
 
-install(TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR})
\ No newline at end of file
+install(TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR})
+
+SET(TEST_SOURCE_ON_SCREEN_LIST test_autozoom_on_screen.cpp)
+
+ADD_EXECUTABLE(test_singleo_on_screen ${TEST_SOURCE_ON_SCREEN_LIST})
+TARGET_COMPILE_DEFINITIONS(test_singleo_on_screen PRIVATE -DTEST_RES_PATH="${TEST_RES_PATH}")
+TARGET_INCLUDE_DIRECTORIES(test_singleo_on_screen PRIVATE ../../capi/ ../../common/include ../../visualizer/include)
+TARGET_LINK_LIBRARIES(test_singleo_on_screen
+    gtest gtest_main pthread singleo_service singleo_visualizer opencv_imgcodecs)
+
+install(TARGETS test_singleo_on_screen DESTINATION ${CMAKE_INSTALL_BINDIR})
diff --git a/test/services/test_autozoom_on_screen.cpp b/test/services/test_autozoom_on_screen.cpp
new file mode 100644 (file)
index 0000000..4e80659
--- /dev/null
@@ -0,0 +1,104 @@
+/**
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <iostream>
+#include <algorithm>
+#include <memory>
+#include <string.h>
+#include <thread>
+
+#include <opencv2/opencv.hpp>
+
+#include "gtest/gtest.h"
+#include "singleo_native_capi_internal.h"
+#include "singleo_util_visualizer_2d.h"
+#include "singleo_error.h"
+
+using namespace testing;
+using namespace std;
+
+void autozoom_callback(void *user_data)
+{
+       singleo_service_h handle = static_cast<singleo_service_h>(user_data);
+       bool is_loop_exit = false;
+       unsigned long frame_number = 0;
+
+       while (!is_loop_exit) {
+               unsigned int cnt;
+
+               int ret = singleo_service_get_result_cnt(handle, &cnt);
+               if (ret != SINGLEO_ERROR_NONE)
+                       break;
+
+               ASSERT_EQ(ret, SINGLEO_ERROR_NONE);
+
+               for (unsigned int idx = 0; idx < cnt; ++idx) {
+                       unsigned int x, y, w, h;
+
+                       ret = singleo_service_get_result_int(handle, idx, "x", &x);
+                       ASSERT_EQ(ret, SINGLEO_ERROR_NONE);
+                       ret = singleo_service_get_result_int(handle, idx, "y", &y);
+                       ASSERT_EQ(ret, SINGLEO_ERROR_NONE);
+                       ret = singleo_service_get_result_int(handle, idx, "width", &w);
+                       ASSERT_EQ(ret, SINGLEO_ERROR_NONE);
+                       ret = singleo_service_get_result_int(handle, idx, "height", &h);
+                       ASSERT_EQ(ret, SINGLEO_ERROR_NONE);
+
+                       cout << x << " x " << y << " ~ " << w << " x " << h << endl;
+               }
+
+               if (++frame_number > 500 && cnt > 0)
+                       is_loop_exit = true;
+       }
+}
+
+void user_callback(unsigned char *buffer, unsigned int width, unsigned int height, unsigned int bytes_per_pixel,
+                                  void *user_data)
+{
+       cv::Mat cv_image(cv::Size(width, height), CV_MAKETYPE(CV_8U, 3), buffer);
+
+       cv::cvtColor(cv_image, cv_image, cv::COLOR_BGR2RGBA);
+
+       cv::Mat resized_image(cv::Size(1600, 900), CV_8UC4, cv::Scalar(0, 0, 0, 0));
+       cv::resize(cv_image, resized_image, resized_image.size());
+
+       singleo_util_visualizer_2d(resized_image, NULL);
+}
+
+TEST(AutoZoomAsyncOnScreenTest, InferenceRequestWithCameraInputFeedShouldBeOk)
+{
+       singleo_service_h handle;
+
+       int ret =
+                       singleo_service_create("service=auto_zoom, input=camera, camera_backend=opencv, fps=30, async=1", &handle);
+       ASSERT_EQ(ret, SINGLEO_ERROR_NONE);
+
+       ret = singleo_service_register_user_callback(handle, user_callback, nullptr);
+       ASSERT_EQ(ret, SINGLEO_ERROR_NONE);
+
+       ret = singleo_service_perform(handle);
+       ASSERT_EQ(ret, SINGLEO_ERROR_NONE);
+
+       unique_ptr<thread> thread_handle = make_unique<thread>(&autozoom_callback, static_cast<void *>(handle));
+
+       thread_handle->join();
+
+       ret = singleo_service_unregister_user_callback(handle);
+       ASSERT_EQ(ret, SINGLEO_ERROR_NONE);
+
+       ret = singleo_service_destroy(handle);
+       ASSERT_EQ(ret, SINGLEO_ERROR_NONE);
+}
diff --git a/visualizer/CMakeLists.txt b/visualizer/CMakeLists.txt
new file mode 100644 (file)
index 0000000..9c3cf99
--- /dev/null
@@ -0,0 +1,35 @@
+project(singleo_visualizer)
+cmake_minimum_required(VERSION 3.13)
+
+execute_process(COMMAND protoc -I=${CMAKE_CURRENT_SOURCE_DIR}
+                ${PROJECT_SOURCE_DIR}/singleo_util_visualizer_rd.proto
+                --cpp_out=${PROJECT_SOURCE_DIR}/src)
+
+execute_process(COMMAND protoc -I=${CMAKE_CURRENT_SOURCE_DIR}
+                ${PROJECT_SOURCE_DIR}/singleo_util_visualizer_rd.proto
+                --grpc_out=${PROJECT_SOURCE_DIR}/src
+                --plugin=protoc-gen-grpc=/usr/bin/grpc_cpp_plugin)
+
+file(GLOB MV_VISUALIZER_SRC_LIST "${PROJECT_SOURCE_DIR}/src/*.cpp"
+                                "${PROJECT_SOURCE_DIR}/src/*.cc")
+
+include(FindPkgConfig)
+
+pkg_check_modules(${PROJECT_NAME}_DEP REQUIRED capi-media-tool libdrm wayland-egl glesv2 dlog protobuf grpc++ re2)
+
+find_package(OpenCV REQUIRED imgproc)
+if(NOT OpenCV_FOUND)
+    message(SEND_ERROR "Failed to find OpenCV")
+    return()
+endif()
+
+add_library(${PROJECT_NAME} SHARED ${MV_VISUALIZER_SRC_LIST})
+target_include_directories(${PROJECT_NAME} PUBLIC
+                           ${${PROJECT_NAME}_DEP_INCLUDE_DIRS}
+                           ${OpenCV_INCLUDE_DIRS}
+                           ${PROJECT_SOURCE_DIR}/include
+                                                  ../common/include
+                           ../log/include)
+target_link_libraries(${PROJECT_NAME} ${${PROJECT_NAME}_DEP_LIBRARIES}
+                        ${OpenCV_LIBS} singleo_log)
+install(TARGETS ${PROJECT_NAME} DESTINATION ${LIB_INSTALL_DIR})
diff --git a/visualizer/include/singleo_util_matrix.h b/visualizer/include/singleo_util_matrix.h
new file mode 100644 (file)
index 0000000..2cb99e9
--- /dev/null
@@ -0,0 +1,36 @@
+/**
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __SINGLEO_UTIL_MATRIX_H__
+#define __SINGLEO_UTIL_MATRIX_H__
+
+int matrix_translate(float *m, float x, float y, float z);
+int matrix_rotate(float *m, float angle, float x, float y, float z);
+int matrix_scale(float *m, float x, float y, float z);
+int matrix_mult(float *m, float *m1, float *m2);
+int matrix_identity(float *m);
+void matrix_copy(float *d, float *s);
+void matrix_invert(float *m);
+void matrix_transpose(float *m);
+void matrix_proj_perspective(float *mat, float fovy, float aspect, float znear, float zfar);
+void quaternion_mult(float *lpR, float *lpP, float *lpQ);
+void quaternion_to_matrix(float *lpM, float *lpQ);
+void quaternion_rotate(float *lpQ, float rad, float ax, float ay, float az);
+void quaternion_identity(float *lpQ);
+void quaternion_copy(float *lpTo, float *lpFrom);
+float vec3_normalize(float *v);
+
+#endif /* __SINGLEO_UTIL_MATRIX_H__ */
diff --git a/visualizer/include/singleo_util_render_2d.h b/visualizer/include/singleo_util_render_2d.h
new file mode 100644 (file)
index 0000000..7ac1993
--- /dev/null
@@ -0,0 +1,41 @@
+/**
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __SINGLEO_UTIL_RENDER_2D_H__
+#define __SINGLEO_UTIL_RENDER_2D_H__
+
+#include <opencv2/opencv.hpp>
+#include <mv_common.h>
+#include <cmath>
+
+#define pixfmt_fourcc(a, b, c, d) ((uint32_t)(a) | ((uint32_t)(b) << 8) | ((uint32_t)(c) << 16) | ((uint32_t)(d) << 24))
+
+typedef struct _texture_2d_t {
+       uint32_t texid;
+       int width;
+       int height;
+       uint32_t format;
+} texture_2d_t;
+
+uint32_t create_2d_texture(void *imgbuf, int width, int height);
+int init_2d_renderer(int w, int h);
+int load_texture(cv::Mat &source, int *lpTexID, int *lpWidth, int *lpHeight);
+int draw_2d_texture(texture_2d_t *tex, int x, int y, int w, int h, int upsidedown);
+int egl_init_with_platform_window_surface(int gles_version, int depth_size, int stencil_size, int sample_num, int win_w,
+                                                                                 int win_h);
+int egl_swap();
+
+#endif /* __SINGLEO_UTIL_RENDER_2D_H__ */
diff --git a/visualizer/include/singleo_util_shader.h b/visualizer/include/singleo_util_shader.h
new file mode 100644 (file)
index 0000000..86d2ec1
--- /dev/null
@@ -0,0 +1,55 @@
+/**
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __SINGLEO_UTIL_SHADER_H__
+#define __SINGLEO_UTIL_SHADER_H__
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#include <cstdlib>
+
+typedef struct shader_obj_t {
+       GLuint program;
+       GLint loc_vtx;
+       GLint loc_nrm;
+       GLint loc_clr;
+       GLint loc_uv;
+       GLint loc_tex;
+       GLint loc_mtx;
+       GLint loc_mtx_nrm;
+} shader_obj_t;
+
+typedef struct _mesh_obj_t {
+       float *vtx_array;
+       float *uv_array;
+       unsigned short *idx_array;
+
+       GLuint vbo_vtx;
+       GLuint vbo_uv;
+       GLuint vbo_idx;
+
+       int num_tile_w;
+       int num_tile_h;
+       int num_idx;
+} mesh_obj_t;
+
+GLuint compile_shader_text(GLenum shaderType, const char *text);
+GLuint link_shaders(GLuint vertShader, GLuint fragShader);
+int generate_shader(shader_obj_t *sobj, char *str_vs, char *str_fs);
+
+#endif /* __SINGLEO_UTIL_SHADER_H__*/
\ No newline at end of file
diff --git a/visualizer/include/singleo_util_visualizer_2d.h b/visualizer/include/singleo_util_visualizer_2d.h
new file mode 100644 (file)
index 0000000..ee9b4dc
--- /dev/null
@@ -0,0 +1,27 @@
+/**
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __SINGLEO_UTIL_VISUALIZER_2D_H__
+#define __SINGLEO_UTIL_VISUALIZER_2D_H__
+
+#include <opencv2/opencv.hpp>
+#include <GLES2/gl2.h>
+
+#include "singleo_util_render_2d.h"
+
+int singleo_util_visualizer_2d(cv::Mat &source, const char *url);
+
+#endif /* __SINGLEO_UTIL_VISUALIZER_2D_H__*/
diff --git a/visualizer/include/singleo_util_winsys.h b/visualizer/include/singleo_util_winsys.h
new file mode 100644 (file)
index 0000000..9afa17c
--- /dev/null
@@ -0,0 +1,47 @@
+/**
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __SINGLEO_UTIL_WINSYS_H_
+#define __SINGLEO_UTIL_WINSYS_H_
+
+struct Window;
+struct Display {
+       struct wl_display *wlDisplay;
+       struct wl_registry *wlRegistry;
+       struct wl_compositor *wlCompositor;
+       struct wl_shell *wlShell;
+       struct wl_pointer *pointer;
+       uint32_t serial;
+       struct Window *window;
+};
+
+struct Geometry {
+       int width, height;
+};
+
+struct Window {
+       struct Display *display;
+       struct wl_egl_window *wlEGLNativeWindow;
+       struct wl_surface *wlSurface;
+       struct wl_shell_surface *wlShellSurface;
+       struct wl_callback *callback;
+       struct Geometry geometry, window_size;
+};
+
+void *winsys_init_native_display(void);
+void *winsys_init_native_window(void *dpy, int win_w, int win_h);
+
+#endif /* __SINGLEO_UTIL_WINSYS_H_ */
diff --git a/visualizer/singleo_util_visualizer_rd.proto b/visualizer/singleo_util_visualizer_rd.proto
new file mode 100644 (file)
index 0000000..ada3f63
--- /dev/null
@@ -0,0 +1,18 @@
+syntax = "proto3";
+
+message Empty {
+}
+
+message NLImage {
+    int32 length = 1;
+    bytes data = 2;
+}
+
+message NLImageDrawRequest {
+    NLImage image = 1;
+}
+
+service NLImageService {
+    rpc DrawImage(NLImageDrawRequest) returns (Empty);
+}
+
diff --git a/visualizer/src/singleo_util_matrix.cpp b/visualizer/src/singleo_util_matrix.cpp
new file mode 100644 (file)
index 0000000..6bd31c9
--- /dev/null
@@ -0,0 +1,872 @@
+/**
+ * Copyright(c) 2022 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0(the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define _USE_MATH_DEFINES
+#include "singleo_util_matrix.h"
+#include <math.h>
+#include <cstring>
+#include "SingleoLog.h"
+#include "singleo_error.h"
+
+static float vec3_length(float *v)
+{
+       return (float) sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
+}
+
+static void turn_x(float *m, float cosA, float sinA)
+{
+       float mx01, mx02;
+       float mx11, mx12;
+       float mx21, mx22;
+       float mx31, mx32;
+
+       mx01 = cosA * m[4];
+       mx02 = sinA * m[4];
+
+       mx11 = cosA * m[5];
+       mx12 = sinA * m[5];
+
+       mx21 = cosA * m[6];
+       mx22 = sinA * m[6];
+
+       mx31 = cosA * m[7];
+       mx32 = sinA * m[7];
+
+       mx01 = sinA * m[8] + mx01;
+       mx02 = cosA * m[8] - mx02;
+
+       mx11 = sinA * m[9] + mx11;
+       mx12 = cosA * m[9] - mx12;
+
+       mx21 = sinA * m[10] + mx21;
+       mx22 = cosA * m[10] - mx22;
+
+       mx31 = sinA * m[11] + mx31;
+       mx32 = cosA * m[11] - mx32;
+
+       m[4] = mx01;
+       m[8] = mx02;
+
+       m[5] = mx11;
+       m[9] = mx12;
+
+       m[6] = mx21;
+       m[10] = mx22;
+
+       m[7] = mx31;
+       m[11] = mx32;
+}
+
+static void turn_y(float *m, float cosA, float sinA)
+{
+       float mx00, mx02;
+       float mx10, mx12;
+       float mx20, mx22;
+       float mx30, mx32;
+
+       mx00 = cosA * m[0];
+       mx02 = sinA * m[0];
+
+       mx10 = cosA * m[1];
+       mx12 = sinA * m[1];
+
+       mx20 = cosA * m[2];
+       mx22 = sinA * m[2];
+
+       mx30 = cosA * m[3];
+       mx32 = sinA * m[3];
+
+       mx00 = -sinA * m[8] + mx00;
+       mx02 = cosA * m[8] + mx02;
+
+       mx10 = -sinA * m[9] + mx10;
+       mx12 = cosA * m[9] + mx12;
+
+       mx20 = -sinA * m[10] + mx20;
+       mx22 = cosA * m[10] + mx22;
+
+       mx30 = -sinA * m[11] + mx30;
+       mx32 = cosA * m[11] + mx32;
+
+       m[0] = mx00;
+       m[8] = mx02;
+
+       m[1] = mx10;
+       m[9] = mx12;
+
+       m[2] = mx20;
+       m[10] = mx22;
+
+       m[3] = mx30;
+       m[11] = mx32;
+}
+
+static void turn_z(float *m, float cosA, float sinA)
+{
+       float mx00, mx01;
+       float mx10, mx11;
+       float mx20, mx21;
+       float mx30, mx31;
+
+       mx00 = cosA * m[0];
+       mx01 = sinA * m[0];
+
+       mx10 = cosA * m[1];
+       mx11 = sinA * m[1];
+
+       mx20 = cosA * m[2];
+       mx21 = sinA * m[2];
+
+       mx30 = cosA * m[3];
+       mx31 = sinA * m[3];
+
+       mx00 = sinA * m[4] + mx00;
+       mx01 = cosA * m[4] - mx01;
+
+       mx10 = sinA * m[5] + mx10;
+       mx11 = cosA * m[5] - mx11;
+
+       mx20 = sinA * m[6] + mx20;
+       mx21 = cosA * m[6] - mx21;
+
+       mx30 = sinA * m[7] + mx30;
+       mx31 = cosA * m[7] - mx31;
+
+       m[0] = mx00;
+       m[4] = mx01;
+       m[1] = mx10;
+       m[5] = mx11;
+       m[2] = mx20;
+       m[6] = mx21;
+       m[3] = mx30;
+       m[7] = mx31;
+}
+
+int matrix_translate(float *m, float x, float y, float z)
+{
+       if (m == NULL) {
+               SINGLEO_LOGE("m is NULL");
+               return SINGLEO_ERROR_EPERM;
+       }
+
+       m[12] += m[8] * z;
+       m[13] += m[9] * z;
+       m[14] += m[10] * z;
+       m[15] += m[11] * z;
+
+       m[12] += m[4] * y;
+       m[13] += m[5] * y;
+       m[14] += m[6] * y;
+       m[15] += m[7] * y;
+
+       m[12] += m[0] * x;
+       m[13] += m[1] * x;
+       m[14] += m[2] * x;
+       m[15] += m[3] * x;
+
+       return SINGLEO_ERROR_NONE;
+}
+
+int matrix_rotate(float *m, float angle, float x, float y, float z)
+{
+       float v[3], angleRadian;
+       float sinA, cosA, cosA2;
+       float xcosA2, ycosA2, zcosA2;
+       float xsinA, ysinA, zsinA;
+
+       if (m == NULL) {
+               SINGLEO_LOGE("m is NULL");
+               return SINGLEO_ERROR_EPERM;
+       }
+
+       angleRadian = angle * (M_PI / 180.0f);
+       sinA = (float) sin(angleRadian);
+       cosA = (float) cos(angleRadian);
+
+       if (x == 0.0f && y == 0.0f && z != 0.0f) {
+               if (z < 0.0f) {
+                       sinA = -sinA;
+               }
+               turn_z(m, cosA, sinA);
+               return SINGLEO_ERROR_NONE;
+       } else if (x == 0.0f && y != 0.0f && z == 0.0f) {
+               if (y < 0.0f) {
+                       sinA = -sinA;
+               }
+               turn_y(m, cosA, sinA);
+               return SINGLEO_ERROR_NONE;
+       } else if (x != 0.0f && y == 0.0f && z == 0.0f) {
+               if (x < 0.0f) {
+                       sinA = -sinA;
+               }
+               turn_x(m, cosA, sinA);
+               return SINGLEO_ERROR_NONE;
+       }
+
+       {
+               float r00, r01, r02;
+               float r10, r11, r12;
+               float r20, r21, r22;
+
+               v[0] = x;
+               v[1] = y;
+               v[2] = z;
+               vec3_normalize(v);
+
+               x = v[0];
+               y = v[1];
+               z = v[2];
+
+               cosA2 = 1.0f - cosA;
+               xsinA = x * sinA;
+               ysinA = y * sinA;
+               zsinA = z * sinA;
+               xcosA2 = x * cosA2;
+               ycosA2 = y * cosA2;
+               zcosA2 = z * cosA2;
+
+               r00 = x * xcosA2 + cosA;
+               r10 = y * xcosA2 + zsinA;
+               r20 = z * xcosA2 - ysinA;
+
+               r01 = x * ycosA2 - zsinA;
+               r11 = y * ycosA2 + cosA;
+               r21 = z * ycosA2 + xsinA;
+
+               r02 = x * zcosA2 + ysinA;
+               r12 = y * zcosA2 - xsinA;
+               r22 = z * zcosA2 + cosA;
+
+               {
+                       float fm0, fm1, fm2;
+                       float mx, my, mz;
+
+                       fm0 = m[0];
+                       fm1 = m[4];
+                       fm2 = m[8];
+
+                       mx = fm0 * r00;
+                       my = fm0 * r01;
+                       mz = fm0 * r02;
+
+                       mx += fm1 * r10;
+                       my += fm1 * r11;
+                       mz += fm1 * r12;
+
+                       mx += fm2 * r20;
+                       my += fm2 * r21;
+                       mz += fm2 * r22;
+
+                       fm0 = m[1];
+                       fm1 = m[5];
+                       fm2 = m[9];
+
+                       m[0] = mx;
+                       m[4] = my;
+                       m[8] = mz;
+
+                       mx = fm0 * r00;
+                       my = fm0 * r01;
+                       mz = fm0 * r02;
+
+                       mx += fm1 * r10;
+                       my += fm1 * r11;
+                       mz += fm1 * r12;
+
+                       mx += fm2 * r20;
+                       my += fm2 * r21;
+                       mz += fm2 * r22;
+
+                       fm0 = m[2];
+                       fm1 = m[6];
+                       fm2 = m[10];
+
+                       m[1] = mx;
+                       m[5] = my;
+                       m[9] = mz;
+
+                       mx = fm0 * r00;
+                       my = fm0 * r01;
+                       mz = fm0 * r02;
+
+                       mx += fm1 * r10;
+                       my += fm1 * r11;
+                       mz += fm1 * r12;
+
+                       mx += fm2 * r20;
+                       my += fm2 * r21;
+                       mz += fm2 * r22;
+
+                       fm0 = m[3];
+                       fm1 = m[7];
+                       fm2 = m[11];
+
+                       m[2] = mx;
+                       m[6] = my;
+                       m[10] = mz;
+
+                       mx = fm0 * r00;
+                       my = fm0 * r01;
+                       mz = fm0 * r02;
+
+                       mx += fm1 * r10;
+                       my += fm1 * r11;
+                       mz += fm1 * r12;
+
+                       mx += fm2 * r20;
+                       my += fm2 * r21;
+                       mz += fm2 * r22;
+
+                       m[3] = mx;
+                       m[7] = my;
+                       m[11] = mz;
+               }
+       }
+
+       return SINGLEO_ERROR_NONE;
+}
+
+int matrix_scale(float *m, float x, float y, float z)
+{
+       float m00, m01, m02, m03;
+       float m04, m05, m06, m07;
+       float m08, m09, m10, m11;
+
+       if (m == NULL) {
+               SINGLEO_LOGE("m is NULL");
+               return SINGLEO_ERROR_EPERM;
+       }
+
+       m00 = m[0];
+       m04 = m[4];
+       m08 = m[8];
+       m01 = m[1];
+       m05 = m[5];
+       m09 = m[9];
+       m02 = m[2];
+       m06 = m[6];
+       m10 = m[10];
+       m03 = m[3];
+       m07 = m[7];
+       m11 = m[11];
+
+       m00 = m00 * x;
+       m04 = m04 * y;
+       m08 = m08 * z;
+
+       m01 = m01 * x;
+       m05 = m05 * y;
+       m09 = m09 * z;
+
+       m02 = m02 * x;
+       m06 = m06 * y;
+       m10 = m10 * z;
+
+       m03 = m03 * x;
+       m07 = m07 * y;
+       m11 = m11 * z;
+
+       m[0] = m00;
+       m[4] = m04;
+       m[8] = m08;
+
+       m[1] = m01;
+       m[5] = m05;
+       m[9] = m09;
+
+       m[2] = m02;
+       m[6] = m06;
+       m[10] = m10;
+
+       m[3] = m03;
+       m[7] = m07;
+       m[11] = m11;
+
+       return SINGLEO_ERROR_NONE;
+}
+
+int matrix_mult(float *m, float *m1, float *m2)
+{
+       float fm0, fm1, fm2, fm3;
+       float fpm00, fpm01, fpm02, fpm03;
+       float fpm10, fpm11, fpm12, fpm13;
+       float fpm20, fpm21, fpm22, fpm23;
+       float fpm30, fpm31, fpm32, fpm33;
+       float x, y, z, w;
+
+       if (m == NULL) {
+               SINGLEO_LOGE("m is NULL");
+               return SINGLEO_ERROR_EPERM;
+       }
+
+       /* load pMb */
+       fpm00 = m2[0];
+       fpm01 = m2[4];
+       fpm02 = m2[8];
+       fpm03 = m2[12];
+
+       fpm10 = m2[1];
+       fpm11 = m2[5];
+       fpm12 = m2[9];
+       fpm13 = m2[13];
+
+       fpm20 = m2[2];
+       fpm21 = m2[6];
+       fpm22 = m2[10];
+       fpm23 = m2[14];
+
+       fpm30 = m2[3];
+       fpm31 = m2[7];
+       fpm32 = m2[11];
+       fpm33 = m2[15];
+
+       fm0 = m1[0];
+       fm1 = m1[4];
+       fm2 = m1[8];
+       fm3 = m1[12];
+
+       x = fm0 * fpm00;
+       y = fm0 * fpm01;
+       z = fm0 * fpm02;
+       w = fm0 * fpm03;
+
+       x += fm1 * fpm10;
+       y += fm1 * fpm11;
+       z += fm1 * fpm12;
+       w += fm1 * fpm13;
+
+       x += fm2 * fpm20;
+       y += fm2 * fpm21;
+       z += fm2 * fpm22;
+       w += fm2 * fpm23;
+
+       x += fm3 * fpm30;
+       y += fm3 * fpm31;
+       z += fm3 * fpm32;
+       w += fm3 * fpm33;
+
+       fm0 = m1[1];
+       fm1 = m1[5];
+       fm2 = m1[9];
+       fm3 = m1[13];
+
+       m[0] = x;
+       m[4] = y;
+       m[8] = z;
+       m[12] = w;
+
+       x = fm0 * fpm00;
+       y = fm0 * fpm01;
+       z = fm0 * fpm02;
+       w = fm0 * fpm03;
+
+       x += fm1 * fpm10;
+       y += fm1 * fpm11;
+       z += fm1 * fpm12;
+       w += fm1 * fpm13;
+
+       x += fm2 * fpm20;
+       y += fm2 * fpm21;
+       z += fm2 * fpm22;
+       w += fm2 * fpm23;
+
+       x += fm3 * fpm30;
+       y += fm3 * fpm31;
+       z += fm3 * fpm32;
+       w += fm3 * fpm33;
+
+       fm0 = m1[2];
+       fm1 = m1[6];
+       fm2 = m1[10];
+       fm3 = m1[14];
+
+       m[1] = x;
+       m[5] = y;
+       m[9] = z;
+       m[13] = w;
+
+       x = fm0 * fpm00;
+       y = fm0 * fpm01;
+       z = fm0 * fpm02;
+       w = fm0 * fpm03;
+
+       x += fm1 * fpm10;
+       y += fm1 * fpm11;
+       z += fm1 * fpm12;
+       w += fm1 * fpm13;
+
+       x += fm2 * fpm20;
+       y += fm2 * fpm21;
+       z += fm2 * fpm22;
+       w += fm2 * fpm23;
+
+       x += fm3 * fpm30;
+       y += fm3 * fpm31;
+       z += fm3 * fpm32;
+       w += fm3 * fpm33;
+
+       fm0 = m1[3];
+       fm1 = m1[7];
+       fm2 = m1[11];
+       fm3 = m1[15];
+
+       m[2] = x;
+       m[6] = y;
+       m[10] = z;
+       m[14] = w;
+
+       x = fm0 * fpm00;
+       y = fm0 * fpm01;
+       z = fm0 * fpm02;
+       w = fm0 * fpm03;
+
+       x += fm1 * fpm10;
+       y += fm1 * fpm11;
+       z += fm1 * fpm12;
+       w += fm1 * fpm13;
+
+       x += fm2 * fpm20;
+       y += fm2 * fpm21;
+       z += fm2 * fpm22;
+       w += fm2 * fpm23;
+
+       x += fm3 * fpm30;
+       y += fm3 * fpm31;
+       z += fm3 * fpm32;
+       w += fm3 * fpm33;
+
+       m[3] = x;
+       m[7] = y;
+       m[11] = z;
+       m[15] = w;
+
+       return SINGLEO_ERROR_NONE;
+}
+
+int matrix_identity(float *m)
+{
+       if (m == NULL) {
+               SINGLEO_LOGE("m is NULL");
+               return SINGLEO_ERROR_EPERM;
+       }
+
+       m[0] = 1.0f;
+       m[4] = 0.0f;
+       m[8] = 0.0f;
+       m[12] = 0.0f;
+       m[1] = 0.0f;
+       m[5] = 1.0f;
+       m[9] = 0.0f;
+       m[13] = 0.0f;
+       m[2] = 0.0f;
+       m[6] = 0.0f;
+       m[10] = 1.0f;
+       m[14] = 0.0f;
+       m[3] = 0.0f;
+       m[7] = 0.0f;
+       m[11] = 0.0f;
+       m[15] = 1.0f;
+
+       return SINGLEO_ERROR_NONE;
+}
+
+void matrix_copy(float *d, float *s)
+{
+       memcpy(d, s, sizeof(float) * 16);
+}
+
+void matrix_transpose(float *m)
+{
+       float m01, m02, m03;
+       float m04, m06, m07;
+       float m08, m09, m11;
+       float m12, m13, m14;
+
+       ;
+       m04 = m[4];
+       m08 = m[8];
+       m12 = m[12];
+       m01 = m[1];
+       m09 = m[9];
+       m13 = m[13];
+       m02 = m[2];
+       m06 = m[6];
+       m14 = m[14];
+       m03 = m[3];
+       m07 = m[7];
+       m11 = m[11];
+
+       /*m[ 0] = m00;*/
+       m[1] = m04;
+       m[2] = m08;
+       m[3] = m12;
+       m[4] = m01;
+       /*m[ 5] = m05;*/
+       m[6] = m09;
+       m[7] = m13;
+       m[8] = m02;
+       m[9] = m06;
+       /*m[10] = m10;*/
+       m[11] = m14;
+       m[12] = m03;
+       m[13] = m07;
+       m[14] = m11;
+       /*m[15] = m15;*/
+}
+
+void matrix_invert(float *m)
+{
+       float m00, m01, m02, m03;
+       float m04, m05, m06, m07;
+       float m08, m09, m10, m11;
+       float m12, m13, m14, m15;
+       float W00, W04, W08, W12;
+       float W01, W05, W09, W13;
+       float W02, W06, W10, W14;
+       float W03, W07, W11, W15;
+       float det, invdet;
+
+       m00 = m[0];
+       m04 = m[4];
+       m08 = m[8];
+       m12 = m[12];
+       m01 = m[1];
+       m05 = m[5];
+       m09 = m[9];
+       m13 = m[13];
+       m02 = m[2];
+       m06 = m[6];
+       m10 = m[10];
+       m14 = m[14];
+       m03 = m[3];
+       m07 = m[7];
+       m11 = m[11];
+       m15 = m[15];
+
+       if (m03 == 0.0f && m07 == 0.0f && m11 == 0.0f && m15 == 1.0f) {
+               W00 = m05 * m10 - m09 * m06;
+               W04 = -(m01 * m10 - m09 * m02);
+               W08 = m01 * m06 - m05 * m02;
+
+               det = m00 * W00 + m04 * W04 + m08 * W08;
+
+               if (det == 0.0f) {
+                       return;
+               }
+               invdet = 1.0f / det;
+
+               W01 = -(m04 * m10 - m08 * m06);
+               W05 = m00 * m10 - m08 * m02;
+               W09 = -(m00 * m06 - m04 * m02);
+
+               W02 = m04 * m09 - m08 * m05;
+               W06 = -(m00 * m09 - m08 * m01);
+               W10 = m00 * m05 - m04 * m01;
+
+               W03 = -(W00 * m12 + W01 * m13 + W02 * m14);
+               W07 = -(W04 * m12 + W05 * m13 + W06 * m14);
+               W11 = -(W08 * m12 + W09 * m13 + W10 * m14);
+
+               /* M^-1[ij] = invdet * M[ji] */
+               m[0] = W00 * invdet;
+               m[4] = W01 * invdet;
+               m[8] = W02 * invdet;
+               m[12] = W03 * invdet;
+
+               m[1] = W04 * invdet;
+               m[5] = W05 * invdet;
+               m[9] = W06 * invdet;
+               m[13] = W07 * invdet;
+
+               m[2] = W08 * invdet;
+               m[6] = W09 * invdet;
+               m[10] = W10 * invdet;
+               m[14] = W11 * invdet;
+
+               m[3] = 0.0f;
+               m[7] = 0.0f;
+               m[11] = 0.0f;
+               m[15] = 1.0f;
+       } else {
+               W00 = (m05 * (m10 * m15 - m14 * m11)) + (m09 * (m14 * m07 - m06 * m15)) + (m13 * (m06 * m11 - m10 * m07));
+               W01 = (m09 * (m14 * m03 - m02 * m15)) + (m13 * (m02 * m11 - m10 * m03)) + (m01 * (m10 * m15 - m14 * m11));
+               W02 = (m13 * (m02 * m07 - m06 * m03)) + (m01 * (m06 * m15 - m14 * m07)) + (m05 * (m14 * m03 - m02 * m15));
+               W03 = (m01 * (m06 * m11 - m10 * m07)) + (m05 * (m10 * m03 - m02 * m11)) + (m09 * (m02 * m07 - m06 * m03));
+               W04 = (m06 * (m11 * m12 - m15 * m08)) + (m10 * (m15 * m04 - m07 * m12)) + (m14 * (m07 * m08 - m11 * m04));
+               W05 = (m10 * (m15 * m00 - m03 * m12)) + (m14 * (m03 * m08 - m11 * m00)) + (m02 * (m11 * m12 - m15 * m08));
+               W06 = (m14 * (m03 * m04 - m07 * m00)) + (m02 * (m07 * m12 - m15 * m04)) + (m06 * (m15 * m00 - m03 * m12));
+               W07 = (m02 * (m07 * m08 - m11 * m04)) + (m06 * (m11 * m00 - m03 * m08)) + (m10 * (m03 * m04 - m07 * m00));
+               W08 = (m07 * (m08 * m13 - m12 * m09)) + (m11 * (m12 * m05 - m04 * m13)) + (m15 * (m04 * m09 - m08 * m05));
+               W09 = (m11 * (m12 * m01 - m00 * m13)) + (m15 * (m00 * m09 - m08 * m01)) + (m03 * (m08 * m13 - m12 * m09));
+               W10 = (m15 * (m00 * m05 - m04 * m01)) + (m03 * (m04 * m13 - m12 * m05)) + (m07 * (m12 * m01 - m00 * m13));
+               W11 = (m03 * (m04 * m09 - m08 * m05)) + (m07 * (m08 * m01 - m00 * m09)) + (m11 * (m00 * m05 - m04 * m01));
+               W12 = (m04 * (m09 * m14 - m13 * m10)) + (m08 * (m13 * m06 - m05 * m14)) + (m12 * (m05 * m10 - m09 * m06));
+               W13 = (m08 * (m13 * m02 - m01 * m14)) + (m12 * (m01 * m10 - m09 * m02)) + (m00 * (m09 * m14 - m13 * m10));
+               W14 = (m12 * (m01 * m06 - m05 * m02)) + (m00 * (m05 * m14 - m13 * m06)) + (m04 * (m13 * m02 - m01 * m14));
+               W15 = (m00 * (m05 * m10 - m09 * m06)) + (m04 * (m09 * m02 - m01 * m10)) + (m08 * (m01 * m06 - m05 * m02));
+
+               det = W00 * m00 - W01 * m04 + W02 * m08 - W03 * m12;
+
+               if (det == 0.0f) {
+                       return;
+               }
+               invdet = 1.0f / det;
+
+               m[0] = W00 * invdet;
+               m[1] = -W01 * invdet;
+               m[2] = W02 * invdet;
+               m[3] = -W03 * invdet;
+               m[4] = -W04 * invdet;
+               m[5] = W05 * invdet;
+               m[6] = -W06 * invdet;
+               m[7] = W07 * invdet;
+               m[8] = W08 * invdet;
+               m[9] = -W09 * invdet;
+               m[10] = W10 * invdet;
+               m[11] = -W11 * invdet;
+               m[12] = -W12 * invdet;
+               m[13] = W13 * invdet;
+               m[14] = -W14 * invdet;
+               m[15] = W15 * invdet;
+       }
+}
+
+void matrix_proj_perspective(float *mat, float fovy, float aspect, float znear, float zfar)
+{
+       float a, b, c, d, f;
+
+       memset(mat, 0x0, sizeof(float) * 16);
+
+       f = (float) (cos(2.0f * 3.14f * (fovy / 2.0f) / 360.0f) / sin(2.0f * 3.14f * (fovy / 2.0f) / 360.0f));
+       a = f / aspect; /* a = f/aspect                */
+       b = f; /* b = f                       */
+       c = (zfar + znear) / (znear - zfar); /* c = (far+near)/(near-far)   */
+       d = (2.0f * zfar * znear) / (znear - zfar); /* d = (2*far*near)/(near-far) */
+
+       mat[0] = a;
+       mat[5] = b;
+       mat[10] = c;
+       mat[11] = -1.0f;
+       mat[14] = d;
+}
+
+/* lpR = lpP * lpQ */
+void quaternion_mult(float *lpR, float *lpP, float *lpQ)
+{
+       float pw, px, py, pz;
+       float qw, qx, qy, qz;
+
+       pw = lpP[0];
+       px = lpP[1];
+       py = lpP[2];
+       pz = lpP[3];
+       qw = lpQ[0];
+       qx = lpQ[1];
+       qy = lpQ[2];
+       qz = lpQ[3];
+
+       lpR[0] = pw * qw - px * qx - py * qy - pz * qz;
+       lpR[1] = pw * qx + px * qw + py * qz - pz * qy;
+       lpR[2] = pw * qy - px * qz + py * qw + pz * qx;
+       lpR[3] = pw * qz + px * qy - py * qx + pz * qw;
+}
+
+void quaternion_to_matrix(float *lpM, float *lpQ)
+{
+       float qw, qx, qy, qz;
+       float x2, y2, z2;
+       float xy, yz, zx;
+       float wx, wy, wz;
+
+       qw = lpQ[0];
+       qx = lpQ[1];
+       qy = lpQ[2];
+       qz = lpQ[3];
+
+       x2 = 2.0f * qx * qx;
+       y2 = 2.0f * qy * qy;
+       z2 = 2.0f * qz * qz;
+
+       xy = 2.0f * qx * qy;
+       yz = 2.0f * qy * qz;
+       zx = 2.0f * qz * qx;
+
+       wx = 2.0f * qw * qx;
+       wy = 2.0f * qw * qy;
+       wz = 2.0f * qw * qz;
+
+       lpM[0] = 1.0f - y2 - z2;
+       lpM[4] = xy - wz;
+       lpM[8] = zx + wy;
+       lpM[12] = 0.0f;
+
+       lpM[1] = xy + wz;
+       lpM[5] = 1.0f - z2 - x2;
+       lpM[9] = yz - wx;
+       lpM[13] = 0.0f;
+
+       lpM[2] = zx - wy;
+       lpM[6] = yz + wx;
+       lpM[10] = 1.0f - x2 - y2;
+       lpM[14] = 0.0f;
+
+       lpM[3] = lpM[7] = lpM[11] = 0.0f;
+       lpM[15] = 1.0f;
+}
+
+void quaternion_rotate(float *lpQ, float rad, float ax, float ay, float az)
+{
+       float hrad = 0.5f * rad;
+       float s = sinf(hrad);
+
+       lpQ[0] = cosf(hrad); /* w */
+       lpQ[1] = s * ax; /* x */
+       lpQ[2] = s * ay; /* y */
+       lpQ[3] = s * az; /* z */
+}
+
+void quaternion_identity(float *lpQ)
+{
+       lpQ[0] = 1.0f; /* w */
+       lpQ[1] = 0.0f; /* x */
+       lpQ[2] = 0.0f; /* y */
+       lpQ[3] = 0.0f; /* z */
+}
+
+void quaternion_copy(float *lpTo, float *lpFrom)
+{
+       lpTo[0] = lpFrom[0]; /* w */
+       lpTo[1] = lpFrom[1]; /* x */
+       lpTo[2] = lpFrom[2]; /* y */
+       lpTo[3] = lpFrom[3]; /* z */
+}
+
+float vec3_normalize(float *v)
+{
+       float len, invLen;
+
+       len = vec3_length(v);
+       if (len == 0.0f)
+               return 0.0f;
+
+       invLen = 1.0f / len;
+
+       v[0] *= invLen;
+       v[1] *= invLen;
+       v[2] *= invLen;
+
+       return len;
+}
diff --git a/visualizer/src/singleo_util_render_2d.cpp b/visualizer/src/singleo_util_render_2d.cpp
new file mode 100644 (file)
index 0000000..c6a44c4
--- /dev/null
@@ -0,0 +1,583 @@
+/**
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#include <cstring>
+#include "SingleoLog.h"
+#include "singleo_error.h"
+
+#include "singleo_util_matrix.h"
+#include "singleo_util_render_2d.h"
+#include "singleo_util_shader.h"
+#include "singleo_util_winsys.h"
+
+static char vs_fill[] = "                             \n\
+                                                      \n\
+attribute vec4 a_Vertex;                              \n\
+uniform mat4 u_PMVMatrix;                             \n\
+void main(void)                                       \n\
+{                                                     \n\
+    gl_Position = u_PMVMatrix * a_Vertex;             \n\
+}                                                     ";
+
+static char fs_fill[] = "                             \n\
+                                                      \n\
+precision mediump float;                              \n\
+uniform vec4 u_Color;                                 \n\
+                                                      \n\
+void main(void)                                       \n\
+{                                                     \n\
+    gl_FragColor = u_Color;                           \n\
+}                                                       ";
+
+static char vs_tex[] = "                              \n\
+attribute vec4 a_Vertex;                              \n\
+attribute vec2 a_TexCoord;                            \n\
+varying vec2 v_TexCoord;                              \n\
+uniform mat4 u_PMVMatrix;                             \n\
+                                                      \n\
+void main(void)                                       \n\
+{                                                     \n\
+    gl_Position = u_PMVMatrix * a_Vertex;             \n\
+    v_TexCoord  = a_TexCoord;                         \n\
+}                                                     \n";
+
+static char fs_tex[] = "                              \n\
+precision mediump float;                              \n\
+varying vec2 v_TexCoord;                              \n\
+uniform sampler2D u_sampler;                          \n\
+uniform vec4 u_Color;                                 \n\
+                                                      \n\
+void main(void)                                       \n\
+{                                                     \n\
+    gl_FragColor = texture2D(u_sampler, v_TexCoord);  \n\
+    gl_FragColor *= u_Color;                          \n\
+}                                                     \n";
+
+static char fs_extex[] = "                            \n\
+#extension GL_NV_EGL_stream_consumer_external: enable \n\
+#extension GL_OES_EGL_image_external : enable         \n\
+precision mediump float;                              \n\
+varying vec2 v_TexCoord;                              \n\
+uniform samplerExternalOES u_sampler;                 \n\
+uniform vec4 u_Color;                                 \n\
+                                                      \n\
+void main(void)                                       \n\
+{                                                     \n\
+    gl_FragColor = texture2D(u_sampler, v_TexCoord);  \n\
+    gl_FragColor *= u_Color;                          \n\
+}                                                     \n";
+
+static char fs_cmap_jet[] = "                          \n\
+precision mediump float;                              \n\
+varying     vec2      v_TexCoord;                     \n\
+uniform     sampler2D u_sampler;                      \n\
+uniform     vec4      u_Color;                        \n\
+                                                      \n\
+float cmap_jet_red(float x)                           \n\
+{                                                     \n\
+    if (x < 0.7) {                                    \n\
+        return 4.0 * x - 1.5;                         \n\
+    } else {                                          \n\
+        return -4.0 * x + 4.5;                        \n\
+    }                                                 \n\
+}                                                     \n\
+                                                      \n\
+float cmap_jet_green(float x)                         \n\
+{                                                     \n\
+    if (x < 0.5) {                                    \n\
+        return 4.0 * x - 0.5;                         \n\
+    } else {                                          \n\
+        return -4.0 * x + 3.5;                        \n\
+    }                                                 \n\
+}                                                     \n\
+                                                      \n\
+float cmap_jet_blue(float x)                          \n\
+{                                                     \n\
+    if (x < 0.3) {                                    \n\
+       return 4.0 * x + 0.5;                          \n\
+    } else {                                          \n\
+       return -4.0 * x + 2.5;                         \n\
+    }                                                 \n\
+}                                                     \n\
+                                                      \n\
+vec4 colormap_jet(float x)                            \n\
+{                                                     \n\
+    float r = clamp(cmap_jet_red(x),   0.0, 1.0);     \n\
+    float g = clamp(cmap_jet_green(x), 0.0, 1.0);     \n\
+    float b = clamp(cmap_jet_blue(x),  0.0, 1.0);     \n\
+    return vec4(r, g, b, 1.0);                        \n\
+}                                                     \n\
+                                                      \n\
+void main(void)                                       \n\
+{                                                     \n\
+    vec4 src_col = texture2D(u_sampler, v_TexCoord);  \n\
+    gl_FragColor = colormap_jet(src_col.r);           \n\
+    gl_FragColor *= u_Color;                          \n\
+}                                                     \n";
+
+static char vs_tex_yuyv[] = "                         \n\
+attribute vec4 a_Vertex;                              \n\
+attribute vec2 a_TexCoord;                            \n\
+varying vec2 v_TexCoord;                              \n\
+varying vec2 v_TexCoordPix;                           \n\
+uniform mat4 u_PMVMatrix;                             \n\
+uniform vec2 u_TexDim;                                \n\
+                                                      \n\
+void main(void)                                       \n\
+{                                                     \n\
+    gl_Position = u_PMVMatrix * a_Vertex;             \n\
+    v_TexCoord = a_TexCoord;                          \n\
+    v_TexCoordPix = a_TexCoord * u_TexDim;            \n\
+}                                                     \n";
+
+static char fs_tex_yuyv[] = "                         \n\
+precision mediump float;                              \n\
+varying vec2 v_TexCoord;                              \n\
+varying vec2 v_TexCoordPix;                           \n\
+uniform sampler2D u_sampler;                          \n\
+uniform vec4 u_Color;                                 \n\
+                                                      \n\
+void main(void)                                       \n\
+{                                                     \n\
+    vec2 evenodd = mod(v_TexCoordPix, 2.0);           \n\
+    vec3 yuv, rgb;                                    \n\
+    vec4 texcol = texture2D(u_sampler, v_TexCoord);   \n\
+    if (evenodd.x < 1.0) {                            \n\
+        yuv.r = texcol.r;       /* Y */               \n\
+        yuv.g = texcol.g - 0.5; /* U */               \n\
+        yuv.b = texcol.a - 0.5; /* V */               \n\
+    } else {                                          \n\
+        yuv.r = texcol.b;       /* Y */               \n\
+        yuv.g = texcol.g - 0.5; /* U */               \n\
+        yuv.b = texcol.a - 0.5; /* V */               \n\
+    }                                                 \n\
+                                                      \n\
+    rgb = mat3 (    1,        1,     1,               \n\
+                    0, -0.34413, 1.772,               \n\
+                1.402, -0.71414,     0) * yuv;        \n\
+    gl_FragColor = vec4(rgb, 1.0);                    \n\
+    gl_FragColor *= u_Color;                          \n\
+}                                                     \n";
+
+#define SHADER_NUM 5
+static char *s_shader[SHADER_NUM * 2] = { vs_fill,     fs_fill, vs_tex,          fs_tex,          vs_tex,
+                                                                                 fs_extex, vs_tex,      fs_cmap_jet, vs_tex_yuyv, fs_tex_yuyv };
+
+static shader_obj_t s_sobj[SHADER_NUM];
+static int s_loc_mtx[SHADER_NUM];
+static int s_loc_color[SHADER_NUM];
+static int s_loc_texdim[SHADER_NUM];
+
+static EGLDisplay s_dpy;
+static EGLSurface s_sfc;
+static EGLContext s_ctx;
+
+GLuint create_2d_texture(void *imgbuf, int width, int height)
+{
+       GLuint texid;
+
+       glGenTextures(1, &texid);
+       glBindTexture(GL_TEXTURE_2D, texid);
+
+       glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+       glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+       glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+       glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+       glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
+
+       glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, imgbuf);
+
+       return texid;
+}
+
+static EGLConfig find_egl_config(int r, int g, int b, int a, int d, int s, int ms, int sfc_type, int ver)
+{
+       EGLint num_conf, i;
+       EGLBoolean ret;
+       EGLConfig conf = 0, *conf_array = NULL;
+
+       EGLint config_attribs[] = { EGL_RED_SIZE,
+                                                               8,
+                                                               EGL_GREEN_SIZE,
+                                                               8,
+                                                               EGL_BLUE_SIZE,
+                                                               8,
+                                                               EGL_ALPHA_SIZE,
+                                                               8,
+                                                               EGL_DEPTH_SIZE,
+                                                               EGL_DONT_CARE,
+                                                               EGL_STENCIL_SIZE,
+                                                               EGL_DONT_CARE,
+                                                               EGL_SAMPLES,
+                                                               EGL_DONT_CARE,
+                                                               EGL_SURFACE_TYPE,
+                                                               EGL_WINDOW_BIT,
+                                                               EGL_RENDERABLE_TYPE,
+                                                               EGL_OPENGL_ES2_BIT,
+                                                               EGL_NONE };
+
+       config_attribs[1] = r;
+       config_attribs[3] = g;
+       config_attribs[5] = b;
+       config_attribs[7] = a;
+       config_attribs[9] = d;
+       config_attribs[11] = s;
+       config_attribs[13] = ms;
+       config_attribs[15] = sfc_type;
+
+       switch (ver) {
+       case 1:
+       case 2:
+               config_attribs[17] = EGL_OPENGL_ES2_BIT;
+               break;
+       default:
+               SINGLEO_LOGE("Invalid version");
+               goto exit;
+       }
+
+       ret = eglChooseConfig(s_dpy, config_attribs, NULL, 0, &num_conf);
+       if (ret != EGL_TRUE || num_conf == 0) {
+               SINGLEO_LOGE("Failed to call eglChooseConfig");
+               goto exit;
+       }
+
+       conf_array = (EGLConfig *) calloc(num_conf, sizeof(EGLConfig));
+       if (conf_array == NULL) {
+               SINGLEO_LOGE("EGLConfig is NULL");
+               goto exit;
+       }
+
+       ret = eglChooseConfig(s_dpy, config_attribs, conf_array, num_conf, &num_conf);
+       if (ret != EGL_TRUE) {
+               SINGLEO_LOGE("Failed to call eglChooseConfig");
+               goto exit;
+       }
+
+       for (i = 0; i < num_conf; i++) {
+               EGLint id, rsize, gsize, bsize, asize;
+
+               eglGetConfigAttrib(s_dpy, conf_array[i], EGL_CONFIG_ID, &id);
+               eglGetConfigAttrib(s_dpy, conf_array[i], EGL_RED_SIZE, &rsize);
+               eglGetConfigAttrib(s_dpy, conf_array[i], EGL_GREEN_SIZE, &gsize);
+               eglGetConfigAttrib(s_dpy, conf_array[i], EGL_BLUE_SIZE, &bsize);
+               eglGetConfigAttrib(s_dpy, conf_array[i], EGL_ALPHA_SIZE, &asize);
+
+               if (rsize == r && gsize == g && bsize == b && asize == a) {
+                       conf = conf_array[i];
+                       break;
+               }
+       }
+
+       if (i == num_conf) {
+               SINGLEO_LOGE("Index is out of range");
+               goto exit;
+       }
+
+exit:
+       free(conf_array);
+
+       return conf;
+}
+
+int egl_init_with_platform_window_surface(int gles_version, int depth_size, int stencil_size, int sample_num, int win_w,
+                                                                                 int win_h)
+{
+       void *native_dpy, *native_win;
+       EGLint major, minor;
+       EGLConfig config;
+       EGLBoolean ret;
+       EGLint context_attribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
+       EGLint sfc_attr[] = { EGL_NONE };
+
+       native_dpy = winsys_init_native_display();
+       if ((native_dpy != EGL_DEFAULT_DISPLAY) && (native_dpy == NULL)) {
+               SINGLEO_LOGE("native_dpy is not valid");
+               return SINGLEO_ERROR_EPERM;
+       }
+
+       s_dpy = eglGetDisplay(native_dpy);
+       if (s_dpy == EGL_NO_DISPLAY) {
+               SINGLEO_LOGE("s_dpy is EGL_NO_DISPLAY");
+               return SINGLEO_ERROR_EPERM;
+       }
+
+       ret = eglInitialize(s_dpy, &major, &minor);
+       if (ret != EGL_TRUE) {
+               SINGLEO_LOGE("Failed to initialize egl");
+               return SINGLEO_ERROR_EPERM;
+       }
+
+       eglBindAPI(EGL_OPENGL_ES_API);
+
+       config = find_egl_config(8, 8, 8, 8, depth_size, stencil_size, sample_num, EGL_WINDOW_BIT, gles_version);
+       if (config == NULL) {
+               SINGLEO_LOGE("Failed to find egl configuration");
+               return SINGLEO_ERROR_EPERM;
+       }
+
+       native_win = winsys_init_native_window(s_dpy, win_w, win_h);
+       if (native_win == NULL) {
+               SINGLEO_LOGE("window is NULL");
+               return SINGLEO_ERROR_EPERM;
+       }
+
+       s_sfc = eglCreateWindowSurface(s_dpy, config, (NativeWindowType) native_win, sfc_attr);
+       if (s_sfc == EGL_NO_SURFACE) {
+               SINGLEO_LOGE("s_sfc is EGL_NO_SURFACE");
+               return SINGLEO_ERROR_EPERM;
+       }
+
+       switch (gles_version) {
+       case 1:
+               context_attribs[1] = 1;
+               break;
+       case 2:
+               context_attribs[1] = 2;
+               break;
+       case 3:
+               context_attribs[1] = 3;
+               break;
+       default:
+               SINGLEO_LOGE("Invalid gles version");
+               return SINGLEO_ERROR_EPERM;
+       }
+
+       s_ctx = eglCreateContext(s_dpy, config, EGL_NO_CONTEXT, context_attribs);
+       if (s_ctx == EGL_NO_CONTEXT) {
+               SINGLEO_LOGE("s_ctx is EGL_NO_CONTEXT");
+               return SINGLEO_ERROR_EPERM;
+       }
+
+       ret = eglMakeCurrent(s_dpy, s_sfc, s_sfc, s_ctx);
+       if (ret != EGL_TRUE) {
+               SINGLEO_LOGE("Failed to call eglMakeCurrent()");
+               return SINGLEO_ERROR_EPERM;
+       }
+
+       return SINGLEO_ERROR_NONE;
+}
+
+int egl_swap()
+{
+       EGLBoolean ret;
+
+       ret = eglSwapBuffers(s_dpy, s_sfc);
+       if (ret != EGL_TRUE) {
+               SINGLEO_LOGE("Failed to call eglSwapBuffers()");
+               return SINGLEO_ERROR_EPERM;
+       }
+
+       return SINGLEO_ERROR_NONE;
+}
+
+static float varray[] = { 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0 };
+
+static float tarray[] = { 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0 };
+
+static float tarray2[] = { 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, 1.0, 0.0 };
+
+static float s_matprj[16];
+static void set_projection_matrix(int w, int h)
+{
+       float mat_proj[] = {
+               0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f, 1.0f
+       };
+
+       mat_proj[0] = 2.0f / (float) w;
+       mat_proj[5] = -2.0f / (float) h;
+
+       memcpy(s_matprj, mat_proj, 16 * sizeof(float));
+}
+
+int init_2d_renderer(int w, int h)
+{
+       int i;
+
+       for (i = 0; i < SHADER_NUM; i++) {
+               if (generate_shader(&s_sobj[i], s_shader[2 * i], s_shader[2 * i + 1]) < 0) {
+                       SINGLEO_LOGE("%s(%d)", __FILE__, __LINE__);
+                       return SINGLEO_ERROR_EPERM;
+               }
+
+               s_loc_mtx[i] = glGetUniformLocation(s_sobj[i].program, "u_PMVMatrix");
+               s_loc_color[i] = glGetUniformLocation(s_sobj[i].program, "u_Color");
+               s_loc_texdim[i] = glGetUniformLocation(s_sobj[i].program, "u_TexDim");
+       }
+
+       set_projection_matrix(w, h);
+
+       return SINGLEO_ERROR_NONE;
+}
+
+typedef struct _texparam {
+       int textype;
+       int texid;
+       int x, y, w, h;
+       int texw, texh;
+       int upsidedown;
+       float color[4];
+       float rot;
+       float px, py;
+       int blendfunc_en;
+       unsigned int blendfunc[4];
+       float *user_texcoord;
+} texparam_t;
+
+static void draw_2d_texture_in(texparam_t *tparam)
+{
+       int ttype = tparam->textype;
+       int texid = tparam->texid;
+       float x = tparam->x;
+       float y = tparam->y;
+       float w = tparam->w;
+       float h = tparam->h;
+       float rot = tparam->rot;
+       shader_obj_t *sobj = &s_sobj[ttype];
+       float matrix[16];
+       float *uv = tarray;
+
+       glBindBuffer(GL_ARRAY_BUFFER, 0);
+       glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+
+       glUseProgram(sobj->program);
+       glUniform1i(sobj->loc_tex, 0);
+
+       switch (ttype) {
+       case 0: /* fill     */
+               break;
+       case 1: /* tex      */
+       case 4: /* tex_yuyv */
+               glBindTexture(GL_TEXTURE_2D, texid);
+               uv = tparam->upsidedown ? tarray2 : tarray;
+               break;
+       case 2: /* tex_extex */
+               glBindTexture(GL_TEXTURE_EXTERNAL_OES, texid);
+               uv = tparam->upsidedown ? tarray : tarray2;
+               break;
+       default:
+               break;
+       }
+
+       if (tparam->user_texcoord)
+               uv = tparam->user_texcoord;
+
+       if (sobj->loc_uv >= 0) {
+               glEnableVertexAttribArray(sobj->loc_uv);
+               glVertexAttribPointer(sobj->loc_uv, 2, GL_FLOAT, GL_FALSE, 0, uv);
+       }
+
+       glEnable(GL_BLEND);
+
+       if (tparam->blendfunc_en) {
+               glBlendFuncSeparate(tparam->blendfunc[0], tparam->blendfunc[1], tparam->blendfunc[2], tparam->blendfunc[3]);
+       } else {
+               glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+       }
+
+       if (matrix_identity(matrix) != SINGLEO_ERROR_NONE)
+               SINGLEO_LOGE("Failed to call matrix_identity");
+       if (matrix_translate(matrix, x, y, 0.0f) != SINGLEO_ERROR_NONE)
+               SINGLEO_LOGE("Failed to call matrix_translate");
+
+       if (rot != 0) {
+               float px = tparam->px;
+               float py = tparam->py;
+               if (matrix_translate(matrix, px, py, 0.0f) != SINGLEO_ERROR_NONE)
+                       SINGLEO_LOGE("Failed to call matrix_translate");
+
+               if (matrix_rotate(matrix, rot, 0.0f, 0.0f, 1.0f) != SINGLEO_ERROR_NONE)
+                       SINGLEO_LOGE("Failed to call matrix_rotate");
+               if (matrix_translate(matrix, -px, -py, 0.0f) != SINGLEO_ERROR_NONE)
+                       SINGLEO_LOGE("Failed to call matrix_translate");
+       }
+       if (matrix_scale(matrix, w, h, 1.0f) != SINGLEO_ERROR_NONE)
+               SINGLEO_LOGE("Failed to call matrix_scale");
+       if (matrix_mult(matrix, s_matprj, matrix) != SINGLEO_ERROR_NONE)
+               SINGLEO_LOGE("Failed to call matrix_mult");
+
+       glUniformMatrix4fv(s_loc_mtx[ttype], 1, GL_FALSE, matrix);
+       glUniform4fv(s_loc_color[ttype], 1, tparam->color);
+
+       if (s_loc_texdim[ttype] >= 0) {
+               float texdim[2];
+               texdim[0] = tparam->texw;
+               texdim[1] = tparam->texh;
+               glUniform2fv(s_loc_texdim[ttype], 1, texdim);
+       }
+
+       if (sobj->loc_vtx >= 0) {
+               glEnableVertexAttribArray(sobj->loc_vtx);
+               glVertexAttribPointer(sobj->loc_vtx, 2, GL_FLOAT, GL_FALSE, 0, varray);
+       }
+
+       glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+
+       glDisable(GL_BLEND);
+}
+
+int load_texture(cv::Mat &source, int *lpTexID, int *lpWidth, int *lpHeight)
+{
+       GLuint texid;
+       int width = source.cols;
+       int height = source.rows;
+
+       texid = create_2d_texture(source.data, source.cols, source.rows);
+
+       if (lpTexID)
+               *lpTexID = texid;
+       if (lpWidth)
+               *lpWidth = width;
+       if (lpHeight)
+               *lpHeight = height;
+
+       return SINGLEO_ERROR_NONE;
+}
+
+int draw_2d_texture(texture_2d_t *tex, int x, int y, int w, int h, int upsidedown)
+{
+       texparam_t tparam = { 0 };
+
+       if (tex == NULL) {
+               SINGLEO_LOGE("tex is NULL");
+               return SINGLEO_ERROR_EPERM;
+       }
+
+       tparam.x = x;
+       tparam.y = y;
+       tparam.w = w;
+       tparam.h = h;
+       tparam.texid = tex->texid;
+       tparam.textype = 1;
+       tparam.texw = tex->width;
+       tparam.texh = tex->height;
+       tparam.color[0] = 1.0f;
+       tparam.color[1] = 1.0f;
+       tparam.color[2] = 1.0f;
+       tparam.color[3] = 1.0f;
+       tparam.upsidedown = upsidedown;
+
+       if (tex->format == pixfmt_fourcc('Y', 'U', 'Y', 'V'))
+               tparam.textype = 4;
+
+       draw_2d_texture_in(&tparam);
+
+       return SINGLEO_ERROR_NONE;
+}
diff --git a/visualizer/src/singleo_util_shader.cpp b/visualizer/src/singleo_util_shader.cpp
new file mode 100644 (file)
index 0000000..30c069f
--- /dev/null
@@ -0,0 +1,117 @@
+/**
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "singleo_util_shader.h"
+#include "SingleoLog.h"
+
+GLuint compile_shader_text(GLenum shaderType, const char *text)
+{
+       GLuint shader;
+       GLint stat;
+
+       shader = glCreateShader(shaderType);
+       glShaderSource(shader, 1, (const char **) &text, NULL);
+       glCompileShader(shader);
+
+       glGetShaderiv(shader, GL_COMPILE_STATUS, &stat);
+       if (!stat) {
+               GLsizei len;
+               char *lpBuf;
+
+               glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &len);
+               lpBuf = (char *) malloc(len);
+
+               glGetShaderInfoLog(shader, len, &len, lpBuf);
+               SINGLEO_LOGE("Error: problem compiling shader.");
+               SINGLEO_LOGE("-----------------------------------");
+               SINGLEO_LOGE("%s", lpBuf);
+               SINGLEO_LOGE("-----------------------------------");
+
+               free(lpBuf);
+
+               return 0;
+       }
+
+       return shader;
+}
+
+GLuint link_shaders(GLuint vertShader, GLuint fragShader)
+{
+       GLuint program = glCreateProgram();
+
+       if (fragShader)
+               glAttachShader(program, fragShader);
+       if (vertShader)
+               glAttachShader(program, vertShader);
+
+       glLinkProgram(program);
+
+       {
+               GLint stat;
+               glGetProgramiv(program, GL_LINK_STATUS, &stat);
+               if (!stat) {
+                       GLsizei len;
+                       char *lpBuf;
+
+                       glGetProgramiv(program, GL_INFO_LOG_LENGTH, &len);
+                       lpBuf = (char *) malloc(len);
+
+                       glGetProgramInfoLog(program, len, &len, lpBuf);
+                       SINGLEO_LOGE("Error: problem linking shader.");
+                       SINGLEO_LOGE("-----------------------------------");
+                       SINGLEO_LOGE("%s", lpBuf);
+                       SINGLEO_LOGE("-----------------------------------");
+
+                       free(lpBuf);
+
+                       return 0;
+               }
+       }
+
+       return program;
+}
+
+int generate_shader(shader_obj_t *sobj, char *str_vs, char *str_fs)
+{
+       GLuint fs, vs, program;
+
+       vs = compile_shader_text(GL_VERTEX_SHADER, str_vs);
+       fs = compile_shader_text(GL_FRAGMENT_SHADER, str_fs);
+       if (vs == 0 || fs == 0) {
+               SINGLEO_LOGE("Failed to compile shader.");
+               return -1;
+       }
+
+       program = link_shaders(vs, fs);
+       if (program == 0) {
+               SINGLEO_LOGE("Failed to link shaders.");
+               return -1;
+       }
+
+       glDeleteShader(vs);
+       glDeleteShader(fs);
+
+       sobj->program = program;
+       sobj->loc_vtx = glGetAttribLocation(program, "a_Vertex");
+       sobj->loc_nrm = glGetAttribLocation(program, "a_Normal");
+       sobj->loc_clr = glGetAttribLocation(program, "a_Color");
+       sobj->loc_uv = glGetAttribLocation(program, "a_TexCoord");
+       sobj->loc_tex = glGetUniformLocation(program, "u_sampler");
+       sobj->loc_mtx = glGetUniformLocation(program, "u_PMVMatrix");
+       sobj->loc_mtx_nrm = glGetUniformLocation(program, "u_NrmMatrix");
+
+       return 0;
+}
diff --git a/visualizer/src/singleo_util_visualizer_2d.cpp b/visualizer/src/singleo_util_visualizer_2d.cpp
new file mode 100644 (file)
index 0000000..92bc273
--- /dev/null
@@ -0,0 +1,141 @@
+/**
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <grpcpp/grpcpp.h>
+
+#include <opencv2/core.hpp>
+#include <opencv2/imgcodecs.hpp>
+#include <opencv2/imgproc/imgproc.hpp>
+#include <opencv2/opencv.hpp>
+
+#include "SingleoLog.h"
+#include "singleo_error.h"
+#include "singleo_util_visualizer_2d.h"
+#include "singleo_util_visualizer_rd.grpc.pb.h"
+
+static int win_w = 1600;
+static int win_h = 900;
+static bool initialized = false;
+
+class ImageClientImpl
+{
+public:
+       ImageClientImpl(std::shared_ptr<grpc::Channel> channel) : stub_(NLImageService::NewStub(channel))
+       {}
+
+       void DrawImage(cv::Mat &source)
+       {
+               cv::cvtColor(source, source, cv::COLOR_RGBA2BGR);
+
+               std::vector<int> qualityType;
+               std::vector<uchar> buff;
+               qualityType.push_back(cv::IMWRITE_JPEG_QUALITY);
+               qualityType.push_back(90);
+               cv::imencode(".jpg", source, buff, qualityType);
+
+               NLImageDrawRequest *request = new NLImageDrawRequest;
+               NLImage tmp;
+               unsigned long length = buff.size();
+
+               std::string str(buff.begin(), buff.end());
+               std::string NLstring(str);
+
+               tmp.set_length(length);
+               tmp.set_data(NLstring);
+
+               request->mutable_image()->set_data(tmp.data());
+               request->mutable_image()->set_length(tmp.length());
+
+               ::Empty reply;
+
+               grpc::ClientContext context;
+               grpc::Status status = stub_->DrawImage(&context, *request, &reply);
+       }
+
+private:
+       std::unique_ptr<NLImageService::Stub> stub_;
+};
+
+static int create_window_surface()
+{
+       int err = SINGLEO_ERROR_NONE;
+       err = egl_init_with_platform_window_surface(2, 8, 0, 0, win_w, win_h);
+       if (SINGLEO_ERROR_NONE != err) {
+               SINGLEO_LOGE("egl_init_with_platform_window_surface: %i", err);
+               return SINGLEO_ERROR_EPERM;
+       }
+       err = init_2d_renderer(win_w, win_h);
+       if (SINGLEO_ERROR_NONE != err) {
+               SINGLEO_LOGE("init_2d_renderer: %i", err);
+               return SINGLEO_ERROR_EPERM;
+       }
+       glClearColor(0.f, 0.f, 0.f, 1.0f);
+       glClear(GL_COLOR_BUFFER_BIT);
+       glViewport(0, 0, win_w, win_h);
+
+       return SINGLEO_ERROR_NONE;
+}
+
+int singleo_util_visualizer_2d(cv::Mat &source, const char *url)
+{
+       int texid;
+       int texw, texh;
+       int err = SINGLEO_ERROR_NONE;
+       texture_2d_t captex = { 0 };
+
+       if (url != NULL) { // remote display
+               ImageClientImpl imageChannel(grpc::CreateChannel(url, grpc::InsecureChannelCredentials()));
+               imageChannel.DrawImage(source);
+
+               return SINGLEO_ERROR_NONE;
+       }
+
+       // target display
+       if (!initialized) {
+               if (create_window_surface() != SINGLEO_ERROR_NONE) {
+                       return SINGLEO_ERROR_EPERM;
+               }
+               initialized = true;
+       }
+
+       err = load_texture(source, &texid, &texw, &texh);
+       if (SINGLEO_ERROR_NONE != err) {
+               SINGLEO_LOGE("load_texture: %i", err);
+               return SINGLEO_ERROR_EPERM;
+       }
+
+       captex.texid = texid;
+       captex.width = texw;
+       captex.height = texh;
+       captex.format = pixfmt_fourcc('R', 'G', 'B', 'A');
+
+       float scale = (float) win_h / (float) texh;
+
+       err = draw_2d_texture(&captex, (win_w - scale * texw) * 0.5f, 0, scale * texw, scale * texh, 0);
+       if (SINGLEO_ERROR_NONE != err) {
+               SINGLEO_LOGE("draw_2d_texture_ex: %i", err);
+               goto out;
+       }
+
+       err = egl_swap();
+       if (SINGLEO_ERROR_NONE != err) {
+               SINGLEO_LOGE("egl_swap: %i", err);
+       }
+
+out:
+       glDeleteTextures(1, reinterpret_cast<GLuint *>(&texid));
+       return err;
+}
diff --git a/visualizer/src/singleo_util_winsys.cpp b/visualizer/src/singleo_util_winsys.cpp
new file mode 100644 (file)
index 0000000..3a2cef5
--- /dev/null
@@ -0,0 +1,135 @@
+/**
+ * Copyright(c) 2022 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0(the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "SingleoLog.h"
+#include "singleo_util_winsys.h"
+#include "wayland-client.h"
+#include "wayland-egl.h"
+#include <signal.h>
+#include <string.h>
+#include <sys/mman.h>
+
+#define UNUSED(x) (void) (x)
+
+struct Display s_display;
+struct Window s_window;
+
+static void handle_ping(void *data, struct wl_shell_surface *wlShellSurface, uint32_t serial)
+{
+       UNUSED(data);
+
+       wl_shell_surface_pong(wlShellSurface, serial);
+}
+
+static void handle_configure(void *data, struct wl_shell_surface *shell_surface, uint32_t edges, int32_t width,
+                                                        int32_t height)
+{
+       struct Window *window = (struct Window *) data;
+       UNUSED(data);
+       UNUSED(shell_surface);
+       UNUSED(edges);
+
+       if (window->wlEGLNativeWindow) {
+               wl_egl_window_resize(window->wlEGLNativeWindow, width, height, 0, 0);
+       }
+
+       window->geometry.width = width;
+       window->geometry.height = height;
+}
+
+static const struct wl_shell_surface_listener shell_surface_listener = { handle_ping, handle_configure, NULL };
+
+static void registry_handle_global(void *data, struct wl_registry *registry, uint32_t name, const char *interface,
+                                                                  uint32_t version)
+{
+       struct Display *d = (struct Display *) data;
+       UNUSED(version);
+
+       if (strcmp(interface, "wl_compositor") == 0) {
+               d->wlCompositor = (wl_compositor *) wl_registry_bind(registry, name, &wl_compositor_interface, 1);
+       } else if (strcmp(interface, "wl_shell") == 0) {
+               d->wlShell = (wl_shell *) wl_registry_bind(registry, name, &wl_shell_interface, 1);
+       }
+}
+
+static void registry_handle_global_remove(void *data, struct wl_registry *registry, uint32_t name)
+{
+       UNUSED(data);
+       UNUSED(registry);
+       UNUSED(name);
+}
+
+static const struct wl_registry_listener registry_listener = { registry_handle_global, registry_handle_global_remove };
+
+void *winsys_init_native_display(void)
+{
+       memset(&s_display, 0, sizeof(s_display));
+
+       s_display.wlDisplay = wl_display_connect(NULL);
+       if (s_display.wlDisplay == NULL) {
+               SINGLEO_LOGE("%s(%d)", __FILE__, __LINE__);
+               return NULL;
+       }
+
+       s_display.wlRegistry = wl_display_get_registry(s_display.wlDisplay);
+       if (s_display.wlRegistry == NULL) {
+               SINGLEO_LOGE("%s(%d)", __FILE__, __LINE__);
+               return NULL;
+       }
+
+       wl_registry_add_listener(s_display.wlRegistry, &registry_listener, &s_display);
+
+       wl_display_dispatch(s_display.wlDisplay);
+
+       return s_display.wlDisplay;
+}
+
+void *winsys_init_native_window(void *dpy, int win_w, int win_h)
+{
+       UNUSED(dpy);
+       memset(&s_window, 0, sizeof(s_window));
+
+       if (!s_display.wlCompositor || !s_display.wlShell) {
+               SINGLEO_LOGE("window compositor or shell is NULL");
+               return NULL;
+       }
+
+       s_window.wlSurface = wl_compositor_create_surface(s_display.wlCompositor);
+       if (s_window.wlSurface == NULL) {
+               SINGLEO_LOGE("window surface is NULL");
+               return NULL;
+       }
+
+       s_window.wlShellSurface = wl_shell_get_shell_surface(s_display.wlShell, s_window.wlSurface);
+       if (s_window.wlShellSurface == NULL) {
+               SINGLEO_LOGE("window shell surface is NULL");
+               return NULL;
+       }
+
+       wl_shell_surface_add_listener(s_window.wlShellSurface, &shell_surface_listener, &s_window);
+
+       s_window.window_size.width = win_w;
+       s_window.window_size.height = win_h;
+       s_window.display = &s_display;
+
+       s_window.wlEGLNativeWindow = wl_egl_window_create(s_window.wlSurface, win_w, win_h);
+       if (s_window.wlEGLNativeWindow == NULL) {
+               SINGLEO_LOGE("window is NULL");
+               return NULL;
+       }
+
+       return s_window.wlEGLNativeWindow;
+}