removed emscripten specific code

pull/3471/head
kallaballa 1 year ago
parent d15063072a
commit 5f19cd08b4
  1. 84
      modules/v4d/CMakeLists.txt
  2. 16
      modules/v4d/include/opencv2/v4d/detail/cl.hpp
  3. 4
      modules/v4d/include/opencv2/v4d/detail/context.hpp
  4. 65
      modules/v4d/include/opencv2/v4d/detail/framebuffercontext.hpp
  5. 2
      modules/v4d/include/opencv2/v4d/detail/gl.hpp
  6. 4
      modules/v4d/include/opencv2/v4d/detail/glcontext.hpp
  7. 4
      modules/v4d/include/opencv2/v4d/detail/imguicontext.hpp
  8. 4
      modules/v4d/include/opencv2/v4d/detail/nanovgcontext.hpp
  9. 42
      modules/v4d/include/opencv2/v4d/util.hpp
  10. 51
      modules/v4d/include/opencv2/v4d/v4d.hpp
  11. 33
      modules/v4d/samples/beauty-demo.cpp
  12. 18
      modules/v4d/samples/cube-demo.cpp
  13. 9
      modules/v4d/samples/custom_source_and_sink.cpp
  14. 6
      modules/v4d/samples/display_image.cpp
  15. 5
      modules/v4d/samples/display_image_fb.cpp
  16. 4
      modules/v4d/samples/display_image_nvg.cpp
  17. 15
      modules/v4d/samples/font-demo.cpp
  18. 22
      modules/v4d/samples/many_cubes-demo.cpp
  19. 15
      modules/v4d/samples/montage-demo.cpp
  20. 14
      modules/v4d/samples/nanovg-demo.cpp
  21. 25
      modules/v4d/samples/optflow-demo.cpp
  22. 21
      modules/v4d/samples/pedestrian-demo.cpp
  23. 22
      modules/v4d/samples/shader-demo.cpp
  24. 27
      modules/v4d/samples/video-demo.cpp
  25. 11
      modules/v4d/samples/video_editing.cpp
  26. 208
      modules/v4d/src/detail/framebuffercontext.cpp
  27. 51
      modules/v4d/src/detail/glcontext.cpp
  28. 121
      modules/v4d/src/detail/imguicontext.cpp
  29. 45
      modules/v4d/src/detail/nanovgcontext.cpp
  30. 16
      modules/v4d/src/detail/sinkcontext.cpp
  31. 19
      modules/v4d/src/detail/sourcecontext.cpp
  32. 181
      modules/v4d/src/util.cpp
  33. 124
      modules/v4d/src/v4d.cpp

@ -52,28 +52,6 @@ macro(fetch_file download_name url hash)
FetchContent_MakeAvailable(${download_name})
endmacro(fetch_file)
# Macro to add a WebAssembly sample
macro(add_emscripten_sample sample source models)
if(NOT (TARGET ${sample}))
ocv_add_executable(${sample} ${source})
ocv_target_include_modules(${sample} opencv_core opencv_imgproc opencv_videoio opencv_video opencv_imgcodecs opencv_v4d opencv_face opencv_tracking opencv_objdetect opencv_stitching opencv_optflow opencv_imgcodecs opencv_features2d opencv_dnn opencv_flann)
ocv_target_link_libraries(${sample} opencv_v4d opencv_core opencv_imgproc opencv_videoio opencv_video opencv_imgcodecs opencv_v4d opencv_face opencv_tracking opencv_objdetect opencv_stitching opencv_optflow opencv_imgcodecs opencv_features2d opencv_dnn opencv_flann)
target_link_directories(${sample} PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/../../lib")
target_include_directories(${sample} PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/include/opencv2/v4d/detail/" "${CMAKE_CURRENT_SOURCE_DIR}/third/imgui" "${CMAKE_CURRENT_SOURCE_DIR}/third/imgui/backends/" "${CMAKE_CURRENT_SOURCE_DIR}/third/nanovg/src/")
target_compile_features(${sample} PRIVATE cxx_std_20)
set_target_properties(${sample} PROPERTIES SUFFIX ".js")
add_custom_command(
TARGET ${sample} PRE_BUILD
COMMAND ${CMAKE_COMMAND} -E copy
"${CMAKE_CURRENT_LIST_DIR}/samples/${sample}.html"
"${CMAKE_CURRENT_BINARY_DIR}/../../bin/${sample}.html")
if(${models})
target_link_options(${sample} PRIVATE "SHELL:--preload-file ${CMAKE_CURRENT_BINARY_DIR}/assets/models/face_detection_yunet_2023mar.onnx")
target_link_options(${sample} PRIVATE "SHELL:--preload-file ${CMAKE_CURRENT_BINARY_DIR}/assets/models/lbfmodel.yaml")
endif()
endif()
endmacro()
# Macro to add a native sample
macro(add_binary_sample sample source)
if(NOT (TARGET ${sample}))
@ -83,31 +61,12 @@ macro(add_binary_sample sample source)
target_compile_features(${sample} PRIVATE cxx_std_20)
target_link_directories(${sample} PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/../../lib")
target_include_directories(${sample} PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/include/" "${CMAKE_CURRENT_SOURCE_DIR}/third/imgui" "${CMAKE_CURRENT_SOURCE_DIR}/third/imgui/backends/" "${CMAKE_CURRENT_SOURCE_DIR}/third/nanovg/src/")
endmacro()
# Configure emscripten build flags
if(EMSCRIPTEN)
set(EM_LINKER_FLAGS "-sENVIRONMENT=web,worker -sWASM_BIGINT=1 -sOFFSCREENCANVAS_SUPPORT -sOFFSCREENCANVASES_TO_PTHREAD=#v4dOffscreenCanvas -sEXPORTED_FUNCTIONS=_main,_v4dInitCapture -sEXPORTED_RUNTIME_METHODS=ccall -sPROXY_TO_PTHREAD=1 --use-preload-plugins --preload-file \"${CMAKE_CURRENT_BINARY_DIR}/assets/fonts/entypo.ttf\" --preload-file \"${CMAKE_CURRENT_BINARY_DIR}/assets/fonts/Roboto-Regular.ttf\" --preload-file \"${CMAKE_CURRENT_BINARY_DIR}/assets/fonts/Roboto-Bold.ttf\" --preload-file \"${CMAKE_CURRENT_BINARY_DIR}/doc/lena.png\" -sINITIAL_MEMORY=128MB -sALLOW_MEMORY_GROWTH=1 -sUSE_GLFW=3 -sMIN_WEBGL_VERSION=2 -sMAX_WEBGL_VERSION=2 --bind")
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${EM_LINKER_FLAGS}")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${EM_LINKER_FLAGS}")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${EM_LINKER_FLAGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
set(EM_DEBUG_FLAGS "-s GL_DEBUG=1 -sSTACK_OVERFLOW_CHECK=2 -sASSERTIONS=2 -sNO_DISABLE_EXCEPTION_CATCHING -sEXCEPTION_DEBUG=1")
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${EM_DEBUG_FLAGS}")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${EM_DEBUG_FLAGS}")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${EM_DEBUG_FLAGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
endif()
endif()
endmacro()
#Configure NanoVG build options
set(NANOVG_BUILD_EXAMPLES OFF)
set(NANOVG_BUILD_GL2 OFF)
if(OPENCV_V4D_ENABLE_ES3 OR EMSCRIPTEN)
if(OPENCV_V4D_ENABLE_ES3)
set(NANOVG_BUILD_GL3 OFF)
set(NANOVG_BUILD_GLES3 ON)
else()
@ -122,13 +81,7 @@ set(NANOVG_USE_FREETYPE OFF)
set(NANOVG_USE_STB ON)
set(CMAKE_CXX_FLAGS "-Wno-error -pthread")
set(CMAKE_C_FLAGS "-Wno-error -pthread")
if(EMSCRIPTEN)
set(CMAKE_CXX_FLAGS "-pthread")
set(CMAKE_C_FLAGS "-pthread")
set(NANOVG_STATIC_LIBS ON)
else()
set(NANOVG_STATIC_LIBS OFF)
endif()
set(NANOVG_STATIC_LIBS OFF)
if (NOT (TARGET nanovg))
add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/third/nanovg/")
@ -136,7 +89,7 @@ if (NOT (TARGET nanovg))
include_directories("${CMAKE_CURRENT_SOURCE_DIR}/third/nanovg/src/")
if(OPENCV_V4D_ENABLE_ES3)
target_link_libraries(nanovg OpenGL::GLES3)
elseif(NOT EMSCRIPTEN)
else()
target_link_libraries(nanovg OpenGL::OpenGL)
endif()
endif()
@ -217,27 +170,6 @@ if(NOT (TARGET ${the_module}))
#Add sample targets
if(BUILD_EXAMPLES)
if(EMSCRIPTEN)
add_emscripten_sample(example_v4d_display_image samples/display_image.cpp false)
add_emscripten_sample(example_v4d_display_image_fb samples/display_image_fb.cpp false)
add_emscripten_sample(example_v4d_display_image_nvg samples/display_image_nvg.cpp false)
add_emscripten_sample(example_v4d_vector_graphics samples/vector_graphics.cpp false)
add_emscripten_sample(example_v4d_vector_graphics_and_fb samples/vector_graphics_and_fb.cpp false)
add_emscripten_sample(example_v4d_render_opengl samples/render_opengl.cpp false)
add_emscripten_sample(example_v4d_custom_source_and_sink samples/custom_source_and_sink.cpp false)
add_emscripten_sample(example_v4d_font_rendering samples/font_rendering.cpp false)
add_emscripten_sample(example_v4d_font_with_gui samples/font_with_gui.cpp false)
add_emscripten_sample(example_v4d_video_editing samples/video_editing.cpp false)
add_emscripten_sample(example_v4d_cube-demo samples/cube-demo.cpp false)
add_emscripten_sample(example_v4d_many_cubes-demo samples/many_cubes-demo.cpp false)
add_emscripten_sample(example_v4d_video-demo samples/video-demo.cpp false)
add_emscripten_sample(example_v4d_nanovg-demo samples/nanovg-demo.cpp false)
add_emscripten_sample(example_v4d_font-demo samples/font-demo.cpp false)
add_emscripten_sample(example_v4d_shader-demo samples/shader-demo.cpp false)
add_emscripten_sample(example_v4d_pedestrian-demo samples/pedestrian-demo.cpp false)
add_emscripten_sample(example_v4d_optflow-demo samples/optflow-demo.cpp false)
add_emscripten_sample(example_v4d_beauty-demo samples/beauty-demo.cpp true)
else()
add_binary_sample(example_v4d_display_image samples/display_image.cpp)
add_binary_sample(example_v4d_display_image_fb samples/display_image_fb.cpp)
add_binary_sample(example_v4d_display_image_nvg samples/display_image_nvg.cpp)
@ -258,7 +190,6 @@ if(NOT (TARGET ${the_module}))
add_binary_sample(example_v4d_optflow-demo samples/optflow-demo.cpp)
add_binary_sample(example_v4d_beauty-demo samples/beauty-demo.cpp)
add_binary_sample(example_v4d_montage-demo samples/montage-demo.cpp)
endif()
endif()
if(OPENCV_V4D_ENABLE_ES3)
@ -266,14 +197,9 @@ if(NOT (TARGET ${the_module}))
endif()
# set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror -Wno-sign-promo")
target_compile_features(${the_module} PRIVATE cxx_std_20)
ocv_warnings_disable(CMAKE_CXX_FLAGS -Wdeprecated-enum-enum-conversion)
target_link_directories(${the_module} PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/../../lib")
if(EMSCRIPTEN)
ocv_target_link_libraries(${the_module} -lnanovg)
else()
ocv_target_link_libraries(${the_module} OpenCL OpenGL GLEW glfw -lnanovg)
endif()
ocv_target_link_libraries(${the_module} OpenCL OpenGL GLEW glfw -lnanovg)
endif()

@ -1,15 +1,13 @@
#ifndef MODULES_V4D_INCLUDE_OPENCV2_V4D_DETAIL_CL_HPP_
#define MODULES_V4D_INCLUDE_OPENCV2_V4D_DETAIL_CL_HPP_
#ifndef __EMSCRIPTEN__
# ifndef CL_TARGET_OPENCL_VERSION
# define CL_TARGET_OPENCL_VERSION 120
# endif
# ifdef __APPLE__
# include <OpenCL/cl_gl_ext.h>
# else
# include <CL/cl_gl.h>
# endif
#ifndef CL_TARGET_OPENCL_VERSION
# define CL_TARGET_OPENCL_VERSION 120
#endif
#ifdef __APPLE__
# include <OpenCL/cl_gl_ext.h>
#else
# include <CL/cl_gl.h>
#endif
#endif /* MODULES_V4D_INCLUDE_OPENCV2_V4D_DETAIL_CL_HPP_ */

@ -23,9 +23,7 @@ class SingleContext : public V4DContext {
public:
virtual ~SingleContext() {}
virtual void execute(std::function<void()> fn) override {
run_sync_on_main<28>([&,this](){
fn();
});
fn();
}
};

@ -6,11 +6,6 @@
#ifndef SRC_OPENCV_FRAMEBUFFERCONTEXT_HPP_
#define SRC_OPENCV_FRAMEBUFFERCONTEXT_HPP_
#ifdef __EMSCRIPTEN__
# include <emscripten/threading.h>
#endif
//FIXME
#include "cl.hpp"
#include "context.hpp"
#include <opencv2/core.hpp>
@ -80,10 +75,8 @@ class CV_EXPORTS FrameBufferContext : public V4DContext {
GLuint textureID_ = 0;
GLuint renderBufferID_ = 0;
GLint viewport_[4];
#ifndef __EMSCRIPTEN__
cl_mem clImage_ = nullptr;
CLExecContext_t context_;
#endif
const cv::Size framebufferSize_;
bool hasParent_ = false;
GLFWwindow* rootWindow_;
@ -126,9 +119,7 @@ public:
class CV_EXPORTS FrameBufferScope {
cv::Ptr<FrameBufferContext> ctx_;
cv::UMat& m_;
#ifndef __EMSCRIPTEN__
std::shared_ptr<ocl::OpenCLExecutionContext> pExecCtx;
#endif
public:
/*!
* Aquires the framebuffer via cl-gl sharing.
@ -137,18 +128,13 @@ public:
*/
CV_EXPORTS FrameBufferScope(cv::Ptr<FrameBufferContext> ctx, cv::UMat& m) :
ctx_(ctx), m_(m)
#ifndef __EMSCRIPTEN__
, pExecCtx(std::static_pointer_cast<ocl::OpenCLExecutionContext>(m.u->allocatorContext))
#endif
{
CV_Assert(!m.empty());
#ifndef __EMSCRIPTEN__
if(pExecCtx) {
CLExecScope_t execScope(*pExecCtx.get());
ctx_->acquireFromGL(m_);
} else
#endif
{
} else {
ctx_->acquireFromGL(m_);
}
}
@ -156,15 +142,11 @@ public:
* Releases the framebuffer via cl-gl sharing.
*/
CV_EXPORTS virtual ~FrameBufferScope() {
#ifndef __EMSCRIPTEN__
if (pExecCtx) {
CLExecScope_t execScope(*pExecCtx.get());
ctx_->releaseToGL(m_);
}
else
#endif
{
else {
ctx_->releaseToGL(m_);
}
}
@ -229,21 +211,16 @@ public:
* @param fn A function object that is passed the framebuffer to be read/manipulated.
*/
virtual void execute(std::function<void()> fn) override {
run_sync_on_main<2>([this,fn](){
#ifndef __EMSCRIPTEN__
if(!getCLExecContext().empty()) {
CLExecScope_t clExecScope(getCLExecContext());
FrameBufferContext::GLScope glScope(self(), GL_FRAMEBUFFER);
FrameBufferContext::FrameBufferScope fbScope(self(), framebuffer_);
fn();
} else
#endif
{
FrameBufferContext::GLScope glScope(self(), GL_FRAMEBUFFER);
FrameBufferContext::FrameBufferScope fbScope(self(), framebuffer_);
fn();
}
});
if(!getCLExecContext().empty()) {
CLExecScope_t clExecScope(getCLExecContext());
FrameBufferContext::GLScope glScope(self(), GL_FRAMEBUFFER);
FrameBufferContext::FrameBufferScope fbScope(self(), framebuffer_);
fn();
} else {
FrameBufferContext::GLScope glScope(self(), GL_FRAMEBUFFER);
FrameBufferContext::FrameBufferScope fbScope(self(), framebuffer_);
fn();
}
}
cv::Vec2f position();
float pixelRatioX();
@ -264,8 +241,7 @@ public:
bool isRoot();
bool hasParent();
bool hasRootWindow();
void fence();
bool wait(const uint64_t& timeout = 0);
/*!
* Blit the framebuffer to the screen
* @param viewport ROI to blit
@ -274,23 +250,14 @@ public:
*/
void blitFrameBufferToFrameBuffer(const cv::Rect& srcViewport, const cv::Size& targetFbSize,
GLuint targetFramebufferID = 0, bool stretch = true, bool flipY = false);
//FIXME make it protected again
#ifndef __EMSCRIPTEN__
/*!
* Get the current OpenCLExecutionContext
* @return The current OpenCLExecutionContext
*/
CLExecContext_t& getCLExecContext();
#endif
protected:
void fence();
bool wait(const uint64_t& timeout = 0);
CLExecContext_t& getCLExecContext();
cv::Ptr<V4D> getV4D();
int getIndex();
void setup();
void teardown();
void initWebGLCopy(const size_t& index);
void doWebGLCopy(cv::Ptr<FrameBufferContext> other);
/*!
* The UMat used to copy or bind (depending on cl-gl interop capability) the OpenGL framebuffer.
*/

@ -7,7 +7,7 @@
#ifndef MODULES_V4D_INCLUDE_OPENCV2_V4D_DETAIL_GL_HPP_
#define MODULES_V4D_INCLUDE_OPENCV2_V4D_DETAIL_GL_HPP_
# if !defined(__EMSCRIPTEN__) && !defined(OPENCV_V4D_USE_ES3)
# if !defined(OPENCV_V4D_USE_ES3)
# include "GL/glew.h"
# define GLFW_INCLUDE_NONE
# else

@ -8,10 +8,6 @@
#include "opencv2/v4d/detail/framebuffercontext.hpp"
#ifdef __EMSCRIPTEN__
#include <emscripten.h>
#endif
struct NVGcontext;
namespace cv {
namespace v4d {

@ -20,10 +20,6 @@
#include "imgui_impl_glfw.h"
#include "imgui_impl_opengl3.h"
#ifdef __EMSCRIPTEN__
#include <emscripten.h>
#endif
namespace cv {
namespace v4d {
namespace detail {

@ -8,10 +8,6 @@
#include "framebuffercontext.hpp"
#ifdef __EMSCRIPTEN__
#include <emscripten.h>
#endif
struct NVGcontext;
namespace cv {
namespace v4d {

@ -19,12 +19,6 @@
#include <opencv2/core/ocl.hpp>
#include <opencv2/imgproc.hpp>
#ifdef __EMSCRIPTEN__
# include <emscripten.h>
# include <emscripten/bind.h>
# include <emscripten/threading.h>
# include <fstream>
#endif
#include <unistd.h>
#include <mutex>
#include <functional>
@ -44,14 +38,9 @@ inline uint64_t get_epoch_nanos() {
}
static thread_local std::mutex mtx_;
static thread_local bool sync_run_ = false;
class CV_EXPORTS ThreadLocal {
public:
CV_EXPORTS static bool& sync_run() {
return sync_run_;
}
CV_EXPORTS static std::mutex& mutex() {
return mtx_;
}
@ -224,23 +213,6 @@ struct Lambda {
}
};
template<std::size_t Tid>
void run_sync_on_main(std::function<void()> fn) {
std::unique_lock<std::mutex> lock(ThreadLocal::mutex());
CV_Assert(fn);
CV_Assert(!ThreadLocal::sync_run());
ThreadLocal::sync_run() = true;
#ifdef __EMSCRIPTEN__
emscripten_sync_run_in_main_runtime_thread(EM_FUNC_SIG_V, cv::v4d::detail::get_fn_ptr<Tid>(fn));
#else
fn();
#endif
ThreadLocal::sync_run() = false;
}
CV_EXPORTS size_t cnz(const cv::UMat& m);
}
using std::string;
@ -254,10 +226,6 @@ class V4D;
*/
CV_EXPORTS cv::Scalar colorConvert(const cv::Scalar& src, cv::ColorConversionCodes code);
#ifdef __EMSCRIPTEN__
CV_EXPORTS Mat read_embedded_image(const string &path);
#endif
/*!
* Convenience function to check for OpenGL errors. Should only be used via the macro #GL_CHECK.
* @param file The file path of the error.
@ -312,7 +280,6 @@ CV_EXPORTS bool keepRunning();
CV_EXPORTS void requestFinish();
#ifndef __EMSCRIPTEN__
/*!
* Creates an Intel VAAPI enabled VideoWriter sink object to use in conjunction with #V4D::setSink().
* Usually you would call #makeWriterSink() and let it automatically decide if VAAPI is available.
@ -353,15 +320,6 @@ CV_EXPORTS cv::Ptr<Sink> makeWriterSink(cv::Ptr<V4D> window, const string& outpu
* @return A (optionally VAAPI enabled) VideoCapture enabled source object.
*/
CV_EXPORTS cv::Ptr<Source> makeCaptureSource(cv::Ptr<V4D> window, const string& inputFilename);
#else
/*!
* Creates a WebCam source object to use in conjunction with #V4D::setSource().
* @param width The frame width to capture (usually the initial width of the V4D object)
* @param height The frame height to capture (usually the initial height of the V4D object)
* @return A WebCam source object.
*/
CV_EXPORTS cv::Ptr<Source> makeCaptureSource(cv::Ptr<V4D> window);
#endif
void resizePreserveAspectRatio(const cv::UMat& src, cv::UMat& output, const cv::Size& dstSize, const cv::Scalar& bgcolor = {0,0,0,255});

@ -6,11 +6,6 @@
#ifndef SRC_OPENCV_V4D_V4D_HPP_
#define SRC_OPENCV_V4D_V4D_HPP_
#ifdef __EMSCRIPTEN__
# include <emscripten.h>
# include <emscripten/threading.h>
#endif
#include "source.hpp"
#include "sink.hpp"
#include "util.hpp"
@ -536,24 +531,6 @@ public:
* @param arr The array to copy.
*/
CV_EXPORTS void copyFrom(const cv::UMat& arr);
/*!
* Execute function object fn in a loop.
* This function main purpose is to abstract the run loop for portability reasons.
* @param fn A functor that will be called repeatetly until the application terminates or the functor returns false
*/
#ifdef __EMSCRIPTEN__
static void do_frame(void* void_fn_ptr) {
glfwSwapInterval(0);
auto* fn_ptr = reinterpret_cast<std::function<bool()>*>(void_fn_ptr);
if (fn_ptr) {
auto& fn = *fn_ptr;
fn();
}
}
#endif
template<typename Tplan>
void run(cv::Ptr<Tplan> plan, int32_t workers = -1) {
@ -631,15 +608,12 @@ public:
}
}
#ifndef __EMSCRIPTEN__
CLExecScope_t scope(this->fbCtx()->getCLExecContext());
#endif
this->fbCtx()->makeCurrent();
#ifndef __EMSCRIPTEN__
if(Global::is_main()) {
this->printSystemInfo();
}
#endif
try {
plan->setup(self());
@ -665,7 +639,6 @@ public:
plan->infer(self());
this->makePlan();
#ifndef __EMSCRIPTEN__
if(Global::is_main()) {
do {
//display with 120hz
@ -689,22 +662,6 @@ public:
reseq.waitFor(seq);
} while(keepRunning() && this->display());
}
#else
if(Global::is_main()) {
std::function<bool()> fnFrame([this](){
this->printSystemInfo();
do {
this->runPlan();
} while(keepRunning() && this->display());
return false;
});
emscripten_set_main_loop_arg(do_frame, &fnFrame, -1, true);
} else {
do {
this->runPlan();
} while(keepRunning() && this->display());
}
#endif
} catch(std::exception& ex) {
requestFinish();
reseq.finish();
@ -902,11 +859,7 @@ protected:
bool wait(uint64_t timeout = 0);
};
}
} /* namespace kb */
#ifdef __EMSCRIPTEN__
# define thread_local
#endif
} /* namespace cv */
#endif /* SRC_OPENCV_V4D_V4D_HPP_ */

@ -115,15 +115,10 @@ private:
float skinSaturation_ = 1.4f;
//Contrast factor skin
float skinContrast_ = 0.7f;
#ifndef __EMSCRIPTEN__
//Show input and output side by side
bool sideBySide_ = false;
//Scale the video to the window size
bool stretch_ = true;
#else
bool sideBySide_ = false;
bool stretch_ = false;
#endif
} params_;
struct Cache {
@ -220,11 +215,9 @@ public:
} else
win->setStretching(false);
#ifndef __EMSCRIPTEN__
if(Button("Fullscreen")) {
win->setFullscreen(!win->isFullscreen());
};
#endif
if(Button("Offscreen")) {
win->setVisible(!win->isVisible());
@ -243,22 +236,13 @@ public:
int w = size().width;
int h = size().height;
downSize_ = { std::min(w, std::max(640, int(round(w / 2.0)))), std::min(h, std::max(360, int(round(h / 2.0)))) };
#ifndef __EMSCRIPTEN__
detector_ = cv::FaceDetectorYN::create("modules/v4d/assets/models/face_detection_yunet_2023mar.onnx", "", downSize_, 0.9, 0.3, 5000, cv::dnn::DNN_BACKEND_OPENCV, cv::dnn::DNN_TARGET_OPENCL);
#else
detector_ = cv::FaceDetectorYN::create("assets/models/face_detection_yunet_2023mar.onnx", "", downSize_, 0.9, 0.3, 5000, cv::dnn::DNN_BACKEND_OPENCV, cv::dnn::DNN_TARGET_CPU);
#endif
int diag = hypot(double(size().width), double(size().height));
params_.blurSkinKernelSize_ = std::max(int(diag / 2000 % 2 == 0 ? diag / 2000 + 1 : diag / 2000), 1);
window->setStretching(params_.stretch_);
window->parallel([](cv::Ptr<cv::face::Facemark>& facemark){
#ifndef __EMSCRIPTEN__
facemark->loadModel("modules/v4d/assets/models/lbfmodel.yaml");
#else
facemark->loadModel("assets/models/lbfmodel.yaml");
#endif
cerr << "Loading finished" << endl;
}, facemark_);
}
void infer(cv::Ptr<V4D> window) override {
@ -397,30 +381,17 @@ public:
BeautyDemoPlan::Params BeautyDemoPlan::params_;
int main(int argc, char **argv) {
#ifndef __EMSCRIPTEN__
if (argc != 2) {
cerr << "Usage: beauty-demo <input-video-file>" << endl;
exit(1);
}
constexpr const char *OUTPUT_FILENAME = "beauty-demo.mkv";
cv::Ptr<BeautyDemoPlan> plan = new BeautyDemoPlan(cv::Size(1920, 1080));
#else
CV_UNUSED(argc);
CV_UNUSED(argv);
cv::Ptr<BeautyDemoPlan> plan = new BeautyDemoPlan(cv::Size(960, 960));
#endif
using namespace cv::v4d;
cv::Ptr<V4D> window = V4D::make(plan->size(), "Beautification Demo", ALL);
#ifndef __EMSCRIPTEN__
auto src = makeCaptureSource(window, argv[1]);
auto sink = makeWriterSink(window, "beauty-demo.mkv", src->fps(), plan->size());
window->setSource(src);
auto sink = makeWriterSink(window, OUTPUT_FILENAME, src->fps(), plan->size());
window->setSink(sink);
#else
auto src = makeCaptureSource(window);
window->setSource(src);
#endif
window->run(plan);
return 0;

@ -67,7 +67,7 @@ private:
static GLuint load_shader() {
//Shader versions "330" and "300 es" are very similar.
//If you are careful you can write the same code for both versions.
#if !defined(__EMSCRIPTEN__) && !defined(OPENCV_V4D_USE_ES3)
#if !defined(OPENCV_V4D_USE_ES3)
const string shaderVersion = "330";
#else
const string shaderVersion = "300 es";
@ -223,34 +223,24 @@ public:
render_scene(v, sp, ut);
}, vao_, shaderProgram_, uniformTransform_);
#ifndef __EMSCRIPTEN__
//Aquire the frame buffer for use by OpenCV
window->fb([](cv::UMat& framebuffer, const cv::Rect& viewport, int glowKernelSize, Cache& cache) {
cv::UMat roi = framebuffer(viewport);
glow_effect(roi, roi, glowKernelSize, cache);
}, viewport(), glowKernelSize_, cache_);
#endif
window->write();
}
};
int main() {
#ifndef __EMSCRIPTEN__
constexpr double FPS = 60;
constexpr const char* OUTPUT_FILENAME = "cube-demo.mkv";
cv::Ptr<CubeDemoPlan> plan = new CubeDemoPlan(cv::Size(1280, 720));
#else
cv::Ptr<CubeDemoPlan> plan = new CubeDemoPlan(cv::Size(960, 960));
#endif
cv::Ptr<V4D> window = V4D::make(plan->size(), "Cube Demo", ALL);
#ifndef __EMSCRIPTEN__
//Creates a writer sink (which might be hardware accelerated)
auto sink = makeWriterSink(window, OUTPUT_FILENAME, FPS, plan->size());
auto sink = makeWriterSink(window, "cube-demo.mkv", 60, plan->size());
window->setSink(sink);
#endif
window->run(plan, 10);
window->run(plan);
return 0;
}

@ -1,7 +1,5 @@
#include <opencv2/v4d/v4d.hpp>
#ifndef __EMSCRIPTEN__
# include <opencv2/imgcodecs.hpp>
#endif
#include <opencv2/imgcodecs.hpp>
using namespace cv;
using namespace cv::v4d;
@ -47,12 +45,7 @@ int main() {
//Make a sink the saves each frame to a PNG file (does nothing in case of WebAssembly).
cv::Ptr<Sink> sink = new Sink([](const uint64_t& seq, const cv::UMat& frame){
try {
#ifndef __EMSCRIPTEN__
imwrite(std::to_string(seq) + ".png", frame);
#else
CV_UNUSED(seq);
CV_UNUSED(frame);
#endif
} catch(std::exception& ex) {
cerr << "Unable to write frame: " << ex.what() << endl;
return false;

@ -12,11 +12,7 @@ public:
void setup(Ptr<V4D> win) override {
win->parallel([](cv::UMat& image){
#ifdef __EMSCRIPTEN__
image = read_embedded_image("doc/lena.png").getUMat(ACCESS_READ);
#else
image = imread(samples::findFile("lena.jpg")).getUMat(ACCESS_READ);
#endif
image = imread(samples::findFile("lena.jpg")).getUMat(ACCESS_READ);
}, image_);
}

@ -14,11 +14,8 @@ public:
void setup(cv::Ptr<V4D> win) override {
win->parallel([](cv::UMat& image, cv::UMat& converted, const cv::Size& sz){
//Loads an image as a UMat (just in case we have hardware acceleration available)
#ifdef __EMSCRIPTEN__
image = read_embedded_image("doc/lena.png").getUMat(ACCESS_READ);
#else
image = imread(samples::findFile("lena.jpg")).getUMat(ACCESS_READ);
#endif
//We have to manually resize and color convert the image when using direct frambuffer access.
resize(image, converted, sz);
cvtColor(converted, converted, COLOR_RGB2BGRA);

@ -18,11 +18,7 @@ public:
void setup(Ptr<V4D> win) override{
//Set the filename
#ifdef __EMSCRIPTEN__
image_.filename_ = "doc/lena.png";
#else
image_.filename_ = samples::findFile("lena.jpg");
#endif
//Creates a NanoVG context. The wrapped C-functions of NanoVG are available in the namespace cv::v4d::nvg;
win->nvg([](Image_t& img) {

@ -11,10 +11,6 @@
#include <sstream>
#include <limits>
#ifdef __EMSCRIPTEN__
#include <emscripten.h>
#endif
using std::string;
using std::vector;
using std::istringstream;
@ -197,20 +193,11 @@ public:
FontDemoPlan::Params FontDemoPlan::params_;
int main() {
#ifndef __EMSCRIPTEN__
cv::Ptr<FontDemoPlan> plan = new FontDemoPlan(cv::Size(1280, 720));
#else
cv::Ptr<FontDemoPlan> plan = new FontDemoPlan(cv::Size(960, 960));
#endif
cv::Ptr<V4D> window = V4D::make(plan->size(), "Font Demo", ALL);
#ifndef __EMSCRIPTEN__
constexpr const char* OUTPUT_FILENAME = "font-demo.mkv";
constexpr double FPS = 60;
auto sink = makeWriterSink(window, OUTPUT_FILENAME, FPS, plan->size());
auto sink = makeWriterSink(window, "font-demo.mkv", 60, plan->size());
window->setSink(sink);
#endif
window->run(plan);
return 0;
}

@ -12,11 +12,8 @@ public:
using Plan::Plan;
/* Demo Parameters */
#ifndef __EMSCRIPTEN__
constexpr static size_t NUMBER_OF_CUBES_ = 10;
#else
constexpr static size_t NUMBER_OF_CUBES_ = 5;
#endif
int glowKernelSize_;
/* OpenGL constants and variables */
@ -71,7 +68,7 @@ private:
static GLuint load_shader() {
//Shader versions "330" and "300 es" are very similar.
//If you are careful you can write the same code for both versions.
#if !defined(__EMSCRIPTEN__) && !defined(OPENCV_V4D_USE_ES3)
#if !defined(OPENCV_V4D_USE_ES3)
const string shaderVersion = "330";
#else
const string shaderVersion = "300 es";
@ -197,7 +194,6 @@ private:
glDrawElements(GL_TRIANGLES, TRIANGLES_ * 3, GL_UNSIGNED_SHORT, NULL);
}
#ifndef __EMSCRIPTEN__
//applies a glow effect to an image
static void glow_effect(const cv::UMat& src, cv::UMat& dst, const int ksize, Cache& cache) {
cv::bitwise_not(src, dst);
@ -217,7 +213,7 @@ private:
cv::bitwise_not(dst, dst);
}
#endif
public:
void setup(cv::Ptr<V4D> window) override {
int diag = hypot(double(size().width), double(size().height));
@ -249,32 +245,22 @@ public:
}
//Aquire the frame buffer for use by OpenCV
#ifndef __EMSCRIPTEN__
window->fb([](cv::UMat& framebuffer, const cv::Rect& viewport, int glowKernelSize, Cache& cache) {
cv::UMat roi = framebuffer(viewport);
glow_effect(roi, roi, glowKernelSize, cache);
}, viewport(), glowKernelSize_, cache_);
#endif
window->write();
}
};
int main() {
#ifndef __EMSCRIPTEN__
cv::Ptr<ManyCubesDemoPlan> plan = new ManyCubesDemoPlan(cv::Size(1280, 720));
#else
cv::Ptr<ManyCubesDemoPlan> plan = new ManyCubesDemoPlan(cv::Size(960, 960));
#endif
cv::Ptr<V4D> window = V4D::make(plan->size(), "Many Cubes Demo", IMGUI);
#ifndef __EMSCRIPTEN_
constexpr double FPS = 60;
constexpr const char* OUTPUT_FILENAME = "many_cubes-demo.mkv";
//Creates a writer sink (which might be hardware accelerated)
auto sink = makeWriterSink(window, OUTPUT_FILENAME, FPS, plan->size());
auto sink = makeWriterSink(window, "many_cubes-demo.mkv", 60, plan->size());
window->setSink(sink);
#endif
window->run(plan, 1);
return 0;

@ -117,28 +117,19 @@ public:
};
int main(int argc, char** argv) {
#ifndef __EMSCRIPTEN__
if (argc != 3) {
cerr << "Usage: montage-demo <video-file> <number of extra workers>" << endl;
exit(1);
}
constexpr double FPS = 60;
constexpr const char* OUTPUT_FILENAME = "montage-demo.mkv";
#else
CV_UNUSED(argc);
CV_UNUSED(argv);
#endif
using namespace cv::v4d;
cv::Ptr<MontageDemoPlan> plan = new MontageDemoPlan(cv::Size(1920, 1080));
cv::Ptr<MontageDemoPlan> plan = new MontageDemoPlan(cv::Size(1920, 1080));
cv::Ptr<V4D> window = V4D::make(plan->size(), "Montage Demo", ALL);
#ifndef __EMSCRIPTEN__
//Creates a source from a file or a device
auto src = makeCaptureSource(window, argv[1]);
window->setSource(src);
//Creates a writer sink (which might be hardware accelerated)
auto sink = makeWriterSink(window, OUTPUT_FILENAME, FPS, plan->size());
auto sink = makeWriterSink(window, "montage-demo.mkv", 60, plan->size());
window->setSink(sink);
#endif
window->run(plan, atoi(argv[2]));
return 0;

@ -165,31 +165,19 @@ public:
};
int main(int argc, char **argv) {
#ifndef __EMSCRIPTEN__
if (argc != 2) {
cerr << "Usage: nanovg-demo <video-file>" << endl;
exit(1);
}
constexpr const char *OUTPUT_FILENAME = "nanovg-demo.mkv";
cv::Ptr<NanoVGDemoPlan> plan = new NanoVGDemoPlan(cv::Size(1280, 960));
#else
CV_UNUSED(argc, argv);
cv::Ptr<NanoVGDemoPlan> plan = new NanoVGDemoPlan(cv::Size(960, 960));
#endif
cv::Ptr<V4D> window = V4D::make(plan->size(), "NanoVG Demo", NANOVG);
window->printSystemInfo();
#ifndef __EMSCRIPTEN__
auto src = makeCaptureSource(window, argv[1]);
auto sink = makeWriterSink(window, OUTPUT_FILENAME, src->fps(), plan->size());
auto sink = makeWriterSink(window, "nanovg-demo.mkv", src->fps(), plan->size());
window->setSource(src);
window->setSink(sink);
#else
auto src = makeCaptureSource(window);
window->setSource(src);
#endif
window->run(plan);

@ -69,11 +69,7 @@ private:
//Stretch frame buffer to window size
bool stretch_ = false;
//The post processing mode
#ifndef __EMSCRIPTEN__
PostProcModes postProcMode_ = GLOW;
#else
PostProcModes postProcMode_ = DISABLED;
#endif
// Intensity of glow or bloom defined by kernel size. The default scales with the image diagonal.
int glowKernelSize_ = 0;
//The lightness selection threshold
@ -366,7 +362,7 @@ public:
if(Checkbox("Stretch", &params.stretch_)) {
win->setStretching(params.stretch_);
}
#ifndef __EMSCRIPTEN__
if(Button("Fullscreen")) {
win->setFullscreen(!win->isFullscreen());
};
@ -374,7 +370,7 @@ public:
if(Button("Offscreen")) {
win->setVisible(!win->isVisible());
};
#endif
End();
}, params_);
}
@ -448,29 +444,18 @@ public:
};
int main(int argc, char **argv) {
CV_UNUSED(argc);
CV_UNUSED(argv);
#ifndef __EMSCRIPTEN__
if (argc != 2) {
std::cerr << "Usage: optflow <input-video-file>" << endl;
exit(1);
}
constexpr const char* OUTPUT_FILENAME = "optflow-demo.mkv";
cv::Ptr<OptflowDemoPlan> plan = new OptflowDemoPlan(cv::Size(1280, 720));
#else
cv::Ptr<OptflowDemoPlan> plan = new OptflowDemoPlan(cv::Size(960, 960));
#endif
cv::Ptr<V4D> window = V4D::make(plan->size(), "Sparse Optical Flow Demo", ALL);
#ifndef __EMSCRIPTEN__
auto src = makeCaptureSource(window, argv[1]);
auto sink = makeWriterSink(window, "optflow-demo.mkv", src->fps(), plan->size());
window->setSource(src);
auto sink = makeWriterSink(window, OUTPUT_FILENAME, src->fps(), plan->size());
window->setSink(sink);
#else
cv::Ptr<Source> src = makeCaptureSource(window);
window->setSource(src);
#endif
window->run(plan);
return 0;

@ -256,37 +256,22 @@ public:
int main(int argc, char **argv) {
CV_UNUSED(argc);
CV_UNUSED(argv);
if (argc != 2) {
std::cerr << "Usage: pedestrian-demo <video-input>" << endl;
exit(1);
}
#ifndef __EMSCRIPTEN__
constexpr const char* OUTPUT_FILENAME = "pedestrian-demo.mkv";
cv::Ptr<PedestrianDemoPlan> plan = new PedestrianDemoPlan(cv::Size(1280, 720));
#else
cv::Ptr<PedestrianDemoPlan> plan = new PedestrianDemoPlan(cv::Size(960, 960));
#endif
using namespace cv::v4d;
cv::Ptr<PedestrianDemoPlan> plan = new PedestrianDemoPlan(cv::Size(1280, 720));
cv::Ptr<V4D> window = V4D::make(plan->size(), "Pedestrian Demo", ALL);
window->printSystemInfo();
#ifndef __EMSCRIPTEN__
auto src = makeCaptureSource(window, argv[1]);
auto sink = makeWriterSink(window, "pedestrian-demo.mkv", src->fps(), plan->size());
window->setSource(src);
auto sink = makeWriterSink(window, OUTPUT_FILENAME, src->fps(), plan->size());
window->setSink(sink);
#else
auto src = makeCaptureSource(WIDTH, HEIGHT, window);
window->setSource(src);
#endif
window->run(plan,0);
window->run(plan);
return 0;
}

@ -102,7 +102,7 @@ private:
//mandelbrot shader code adapted from my own project: https://github.com/kallaballa/FractalDive#after
static GLuint load_shader() {
#if !defined(__EMSCRIPTEN__) && !defined(OPENCV_V4D_USE_ES3)
#if !defined(OPENCV_V4D_USE_ES3)
const string shaderVersion = "330";
#else
const string shaderVersion = "300 es";
@ -315,34 +315,18 @@ public:
ShaderDemoPlan::Params ShaderDemoPlan::params_;
int main(int argc, char** argv) {
CV_UNUSED(argc);
CV_UNUSED(argv);
#ifndef __EMSCRIPTEN__
if (argc != 2) {
cerr << "Usage: shader-demo <video-file>" << endl;
exit(1);
}
cv::Ptr<ShaderDemoPlan> plan = new ShaderDemoPlan(cv::Size(1280, 720));
#else
cv::Ptr<ShaderDemoPlan> plan = new ShaderDemoPlan(cv::Size(960, 960));
#endif
cv::Ptr<ShaderDemoPlan> plan = new ShaderDemoPlan(cv::Size(1280, 720));
cv::Ptr<V4D> window = V4D::make(plan->size(), "Mandelbrot Shader Demo", IMGUI);
#ifndef __EMSCRIPTEN_
constexpr const char* OUTPUT_FILENAME = "shader-demo.mkv";
//Creates a source from a file or a device
auto src = makeCaptureSource(window, argv[1]);
auto sink = makeWriterSink(window, "shader-demo.mkv", src->fps(), plan->size());
window->setSource(src);
auto sink = makeWriterSink(window, OUTPUT_FILENAME, src->fps(), plan->size());
window->setSink(sink);
#else
//Creates a source from a file or a device
auto src = makeCaptureSource(window);
window->setSource(src);
#endif
window->run(plan);

@ -69,7 +69,7 @@ private:
GLuint uniform_transform_ = 0;
static GLuint load_shader() {
#if !defined(__EMSCRIPTEN__) && !defined(OPENCV_V4D_USE_ES3)
#if !defined(OPENCV_V4D_USE_ES3)
const string shaderVersion = "330";
#else
const string shaderVersion = "300 es";
@ -168,7 +168,6 @@ private:
}
#ifndef __EMSCRIPTEN__
static void glow_effect(const cv::UMat& src, cv::UMat& dst, const int ksize, Cache& cache) {
cv::bitwise_not(src, dst);
@ -182,7 +181,6 @@ private:
cv::bitwise_not(dst, dst);
}
#endif
public:
void setup(cv::Ptr<V4D> window) override {
int diag = hypot(double(size().width), double(size().height));
@ -199,49 +197,28 @@ public:
render_scene(vao, shader, uniformTrans);
}, vao_, shader_, uniform_transform_);
#ifndef __EMSCRIPTEN__
window->fb([](cv::UMat& framebuffer, const cv::Rect& viewport, int glowKernelSize, Cache& cache) {
cv::UMat roi = framebuffer(viewport);
glow_effect(roi, roi, glowKernelSize, cache);
}, viewport(), glowKernelSize_, cache_);
#endif
//Ignored in WebAssmebly builds because there is no sink set.
window->write();
}
};
int main(int argc, char** argv) {
#ifndef __EMSCRIPTEN__
if (argc != 2) {
cerr << "Usage: video-demo <video-file>" << endl;
exit(1);
}
constexpr const char* OUTPUT_FILENAME = "video-demo.mkv";
cv::Ptr<VideoDemoPlan> plan = new VideoDemoPlan(cv::Size(1280,720));
#else
CV_UNUSED(argc);
CV_UNUSED(argv);
cv::Ptr<VideoDemoPlan> plan = new VideoDemoPlan(cv::Size(960,960));
#endif
using namespace cv::v4d;
cv::Ptr<V4D> window = V4D::make(plan->size(), "Video Demo", NONE);
#ifndef __EMSCRIPTEN__
//Creates a source from a file or a device
auto src = makeCaptureSource(window, argv[1]);
auto sink = makeWriterSink(window, "video-demo.mkv", src->fps(), plan->size());
window->setSource(src);
auto sink = makeWriterSink(window, OUTPUT_FILENAME, src->fps(), plan->size());
window->setSink(sink);
#else
//Creates a webcam source is available
auto src = makeCaptureSource(window);
window->setSource(src);
#endif
window->run(plan);

@ -31,27 +31,18 @@ public:
};
int main(int argc, char** argv) {
//In case of WebAssembly
CV_UNUSED(argc);
CV_UNUSED(argv);
Ptr<VideoEditingPlan> plan = new VideoEditingPlan(cv::Size(960,960));
Ptr<V4D> window = V4D::make(plan->size(), "Video Editing");
#ifndef __EMSCRIPTEN__
//Make the video source
auto src = makeCaptureSource(window, argv[1]);
//Make the video sink
auto sink = makeWriterSink(window, argv[2], src->fps(), plan->size());
//Attach source and sink
window->setSource(src);
window->setSink(sink);
#else
//Make a webcam Source
auto src = makeCaptureSource(window);
//Attach webcam source
window->setSource(src);
#endif
window->run(plan);
}

@ -12,11 +12,6 @@
#include "imgui_impl_glfw.h"
#ifdef __EMSCRIPTEN__
# include <emscripten.h>
# include <emscripten/bind.h>
#endif
namespace cv {
namespace v4d {
@ -40,7 +35,7 @@ FrameBufferContext::FrameBufferContext(V4D& v4d, const cv::Size& framebufferSize
const string& title, int major, int minor, int samples, bool debug, GLFWwindow* rootWindow, cv::Ptr<FrameBufferContext> parent, bool root) :
v4d_(&v4d), offscreen_(offscreen), title_(title), major_(major), minor_(
minor), samples_(samples), debug_(debug), isVisible_(offscreen), viewport_(0, 0, framebufferSize.width, framebufferSize.height), framebufferSize_(framebufferSize), hasParent_(false), rootWindow_(rootWindow), parent_(parent), framebuffer_(), isRoot_(root) {
run_sync_on_main<1>([this](){ init(); });
init();
index_ = ++frameBufferContextCnt;
}
@ -58,7 +53,7 @@ GLuint FrameBufferContext::getTextureID() {
void FrameBufferContext::loadShader(const size_t& index) {
#if !defined(__EMSCRIPTEN__) && !defined(OPENCV_V4D_USE_ES3)
#if !defined(OPENCV_V4D_USE_ES3)
const string shaderVersion = "330";
#else
const string shaderVersion = "300 es";
@ -119,96 +114,10 @@ void FrameBufferContext::loadBuffers(const size_t& index) {
glBindVertexArray(0);
}
void FrameBufferContext::initWebGLCopy(const size_t& index) {
#ifdef __EMSCRIPTEN__
this->makeCurrent();
GL_CHECK(glGenFramebuffers(1, &copyFramebuffers_[index]));
GL_CHECK(glGenTextures(1, &copyTextures_[index]));
loadShader(index);
loadBuffers(index);
// lookup the sampler locations.
texture_hdls_[index] = glGetUniformLocation(shader_program_hdls_[index], "texture0");
resolution_hdls_[index] = glGetUniformLocation(shader_program_hdls_[index], "resolution");
#else
CV_UNUSED(index);
CV_Error(Error::StsNotImplemented, "WebGL not supported in none WASM builds");
#endif
}
void FrameBufferContext::doWebGLCopy(cv::Ptr<FrameBufferContext> other) {
#ifdef __EMSCRIPTEN__
cerr << "do copy" << endl;
size_t index = other->getIndex();
this->makeCurrent();
int width = getWindowSize().width;
int height = getWindowSize().height;
{
FrameBufferContext::GLScope glScope(self(), GL_READ_FRAMEBUFFER);
other->blitFrameBufferToFrameBuffer(
cv::Rect(0,0, other->size().width, other->size().height),
this->getWindowSize(),
0, false);
emscripten_webgl_commit_frame();
}
this->makeCurrent();
GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, copyFramebuffers_[index]));
GL_CHECK(glBindTexture(GL_TEXTURE_2D, copyTextures_[index]));
EM_ASM({
var gl = Module.ctx;
var canvas;
if($0 > 0)
canvas = document.getElementById('canvas' + $0);
else
canvas = document.getElementById('canvas');
if(typeof Module["copyFramebuffers" + $0] === 'undefined') {
Module["copyFramebuffers" + $0] = gl.getParameter(gl.FRAMEBUFFER_BINDING);
}
if(typeof Module["copyTextures" + $0] === 'undefined') {
Module["copyTextures" + $0]= gl.getParameter(gl.TEXTURE_BINDING_2D);
}
gl.enable(gl.BLEND);
gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
gl.bindFramebuffer(gl.FRAMEBUFFER, Module["copyFramebuffers" + $0]);
gl.bindTexture(gl.TEXTURE_2D, Module["copyTextures" + $0] );
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, canvas);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT1, gl.TEXTURE_2D, Module["copyTextures" + $0] , 0);
}, index - 1);
assert(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
GL_CHECK(glReadBuffer(GL_COLOR_ATTACHMENT1));
GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, this->getFramebufferID()));
glViewport(0, 0, width, height);
GL_CHECK(glUseProgram(shader_program_hdls_[index]));
// set which texture units to render with.
GL_CHECK(glUniform1i(texture_hdls_[index], 0)); // texture unit 0
float res[2] = {float(width), float(height)};
GL_CHECK(glUniform2fv(resolution_hdls_[index], 1, res));
// Set each texture unit to use a particular texture.
GL_CHECK(glActiveTexture(GL_TEXTURE0));
GL_CHECK(glBindTexture(GL_TEXTURE_2D, copyTextures_[index]));
GL_CHECK(glBindVertexArray(copyVaos[index]));
GL_CHECK(glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0));
GL_CHECK(glDisable(GL_BLEND));
#else
CV_UNUSED(other);
CV_Error(Error::StsNotImplemented, "WebGL not supported in none WASM builds");
#endif
}
void FrameBufferContext::init() {
static std::mutex initMtx;
std::unique_lock<std::mutex> lock(initMtx);
#if !defined(__EMSCRIPTEN__)
if(parent_) {
hasParent_ = true;
@ -223,14 +132,11 @@ void FrameBufferContext::init() {
onscreenTextureID_ = parent_->onscreenTextureID_;
onscreenRenderBufferID_ = parent_->onscreenRenderBufferID_;
}
}
#else
hasParent_ = false;
#endif
if (!parent_ && glfwInit() != GLFW_TRUE) {
cerr << "Can't init GLFW" << endl;
} else if (glfwInit() != GLFW_TRUE) {
cerr << "Can't init GLFW" << endl;
exit(1);
}
glfwSetErrorCallback(cv::v4d::detail::glfw_error_callback);
if (debug_)
@ -242,7 +148,7 @@ void FrameBufferContext::init() {
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
#elif defined(OPENCV_V4D_USE_ES3) || defined(__EMSCRIPTEN__)
#elif defined(OPENCV_V4D_USE_ES3)
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
glfwWindowHint(GLFW_CONTEXT_CREATION_API, GLFW_EGL_CONTEXT_API);
@ -262,11 +168,7 @@ void FrameBufferContext::init() {
glfwWindowHint(GLFW_STENCIL_BITS, 8);
glfwWindowHint(GLFW_DEPTH_BITS, 24);
glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE);
#ifndef __EMSCRIPTEN__
glfwWindowHint(GLFW_VISIBLE, offscreen_ ? GLFW_FALSE : GLFW_TRUE );
#else
glfwWindowHint(GLFW_VISIBLE, GLFW_TRUE);
#endif
glfwWindowHint(GLFW_DOUBLEBUFFER, GLFW_TRUE);
glfwWindow_ = glfwCreateWindow(framebufferSize_.width, framebufferSize_.height, title_.c_str(), nullptr,
@ -290,10 +192,9 @@ void FrameBufferContext::init() {
rootWindow_ = glfwWindow_;
this->makeCurrent();
#ifndef __EMSCRIPTEN__
glfwSwapInterval(0);
#endif
#if !defined(OPENCV_V4D_USE_ES3) && !defined(__EMSCRIPTEN__)
//FIXME?
//#if !defined(OPENCV_V4D_USE_ES3)
if (!parent_) {
GLenum err = glewInit();
if (err != GLEW_OK && err != GLEW_ERROR_NO_GLX_DISPLAY) {
@ -312,12 +213,11 @@ void FrameBufferContext::init() {
CV_LOG_WARNING(nullptr, "CL-GL sharing failed with unknown error");
clglSharing_ = false;
}
#else
clglSharing_ = false;
#endif
#ifndef __EMSCRIPTEN__
//#else
// clglSharing_ = false;
//#endif
context_ = CLExecContext_t::getCurrent();
#endif
setup();
glfwSetWindowUserPointer(getGLFWWindow(), getV4D().get());
@ -405,7 +305,6 @@ void FrameBufferContext::init() {
//// if(v4d->hasNguiCtx())
//// v4d->nguiCtx().screen().resize_callback_event(width, height);
//// });
//// #ifndef __EMSCRIPTEN__
//// if(v4d->isResizable()) {
//// v4d->nvgCtx().fbCtx()->teardown();
//// v4d->glCtx().fbCtx()->teardown();
@ -414,7 +313,6 @@ void FrameBufferContext::init() {
//// v4d->glCtx().fbCtx()->setup(cv::Size(width, height));
//// v4d->nvgCtx().fbCtx()->setup(cv::Size(width, height));
//// }
//// #endif
// });
glfwSetWindowFocusCallback(getGLFWWindow(), [](GLFWwindow* glfwWin, int i) {
V4D* v4d = reinterpret_cast<V4D*>(glfwGetWindowUserPointer(glfwWin));
@ -434,9 +332,7 @@ int FrameBufferContext::getIndex() {
void FrameBufferContext::setup() {
cv::Size sz = framebufferSize_;
#ifndef __EMSCRIPTEN__
CLExecScope_t clExecScope(getCLExecContext());
#endif
framebuffer_.create(sz, CV_8UC4);
if(isRoot()) {
GL_CHECK(glGenFramebuffers(1, &frameBufferID_));
@ -487,7 +383,6 @@ void FrameBufferContext::teardown() {
using namespace cv::ocl;
this->makeCurrent();
#ifndef __EMSCRIPTEN__
if(clImage_ != nullptr && !getCLExecContext().empty()) {
CLExecScope_t clExecScope(getCLExecContext());
@ -507,7 +402,6 @@ void FrameBufferContext::teardown() {
CV_Error_(cv::Error::OpenCLApiCallError, ("OpenCL: clReleaseMemObject failed: %d", status));
clImage_ = nullptr;
}
#endif
glBindTexture(GL_TEXTURE_2D, 0);
glGetError();
glBindRenderbuffer(GL_RENDERBUFFER, 0);
@ -523,10 +417,6 @@ void FrameBufferContext::teardown() {
}
void FrameBufferContext::toGLTexture2D(cv::UMat& u, cv::ogl::Texture2D& texture) {
#ifdef __EMSCRIPTEN__
CV_UNUSED(u);
CV_UNUSED(texture);
#else
using namespace cv::ocl;
cl_int status = 0;
@ -558,14 +448,9 @@ void FrameBufferContext::toGLTexture2D(cv::UMat& u, cv::ogl::Texture2D& texture)
status = clFinish(q);
if (status != CL_SUCCESS)
throw std::runtime_error("OpenCL: clFinish failed: " + std::to_string(status));
#endif
}
void FrameBufferContext::fromGLTexture2D(const cv::ogl::Texture2D& texture, cv::UMat& u) {
#ifdef __EMSCRIPTEN__
CV_UNUSED(u);
CV_UNUSED(texture);
#else
using namespace cv::ocl;
const int dtype = CV_8UC4;
@ -608,7 +493,6 @@ void FrameBufferContext::fromGLTexture2D(const cv::ogl::Texture2D& texture, cv::
status = clFinish(q);
if (status != CL_SUCCESS)
throw std::runtime_error("OpenCL: clFinish failed: " + std::to_string(status));
#endif
}
const cv::Size& FrameBufferContext::size() const {
@ -616,41 +500,29 @@ const cv::Size& FrameBufferContext::size() const {
}
void FrameBufferContext::copyTo(cv::UMat& dst) {
run_sync_on_main<7>([&,this](){
#ifndef __EMSCRIPTEN__
if(!getCLExecContext().empty()) {
CLExecScope_t clExecScope(getCLExecContext());
#endif
FrameBufferContext::GLScope glScope(this, GL_FRAMEBUFFER);
FrameBufferContext::FrameBufferScope fbScope(this, framebuffer_);
framebuffer_.copyTo(dst);
#ifndef __EMSCRIPTEN__
} else {
FrameBufferContext::GLScope glScope(this, GL_FRAMEBUFFER);
FrameBufferContext::FrameBufferScope fbScope(this, framebuffer_);
framebuffer_.copyTo(dst);
}
#endif
});
if(!getCLExecContext().empty()) {
CLExecScope_t clExecScope(getCLExecContext());
FrameBufferContext::GLScope glScope(this, GL_FRAMEBUFFER);
FrameBufferContext::FrameBufferScope fbScope(this, framebuffer_);
framebuffer_.copyTo(dst);
} else {
FrameBufferContext::GLScope glScope(this, GL_FRAMEBUFFER);
FrameBufferContext::FrameBufferScope fbScope(this, framebuffer_);
framebuffer_.copyTo(dst);
}
}
void FrameBufferContext::copyFrom(const cv::UMat& src) {
run_sync_on_main<18>([&,this](){
#ifndef __EMSCRIPTEN__
if(!getCLExecContext().empty()) {
CLExecScope_t clExecScope(getCLExecContext());
#endif
FrameBufferContext::GLScope glScope(this, GL_FRAMEBUFFER);
FrameBufferContext::FrameBufferScope fbScope(this, framebuffer_);
src.copyTo(framebuffer_);
#ifndef __EMSCRIPTEN__
} else {
FrameBufferContext::GLScope glScope(this, GL_FRAMEBUFFER);
FrameBufferContext::FrameBufferScope fbScope(this, framebuffer_);
src.copyTo(framebuffer_);
}
#endif
});
if(!getCLExecContext().empty()) {
CLExecScope_t clExecScope(getCLExecContext());
FrameBufferContext::GLScope glScope(this, GL_FRAMEBUFFER);
FrameBufferContext::FrameBufferScope fbScope(this, framebuffer_);
src.copyTo(framebuffer_);
} else {
FrameBufferContext::GLScope glScope(this, GL_FRAMEBUFFER);
FrameBufferContext::FrameBufferScope fbScope(this, framebuffer_);
src.copyTo(framebuffer_);
}
}
void FrameBufferContext::copyToRootWindow() {
@ -670,11 +542,9 @@ GLFWwindow* FrameBufferContext::getGLFWWindow() const {
return glfwWindow_;
}
#ifndef __EMSCRIPTEN__
CLExecContext_t& FrameBufferContext::getCLExecContext() {
return context_;
}
#endif
void FrameBufferContext::blitFrameBufferToFrameBuffer(const cv::Rect& srcViewport,
const cv::Size& targetFbSize, GLuint targetFramebufferID, bool stretch, bool flipY) {
@ -791,29 +661,17 @@ cv::Vec2f FrameBufferContext::position() {
}
float FrameBufferContext::pixelRatioX() {
#ifdef __EMSCRIPTEN__
float r = emscripten_get_device_pixel_ratio();
return r;
#else
float xscale, yscale;
glfwGetWindowContentScale(getGLFWWindow(), &xscale, &yscale);
return xscale;
#endif
}
float FrameBufferContext::pixelRatioY() {
#ifdef __EMSCRIPTEN__
float r = emscripten_get_device_pixel_ratio();
return r;
#else
float xscale, yscale;
glfwGetWindowContentScale(getGLFWWindow(), &xscale, &yscale);
return yscale;
#endif
}
void FrameBufferContext::makeCurrent() {
@ -822,9 +680,7 @@ void FrameBufferContext::makeCurrent() {
}
void FrameBufferContext::makeNoneCurrent() {
#ifndef __EMSCRIPTEN__
glfwMakeContextCurrent(nullptr);
#endif
}

@ -11,45 +11,24 @@ namespace v4d {
namespace detail {
GLContext::GLContext(const int32_t& idx, cv::Ptr<FrameBufferContext> fbContext) :
idx_(idx), mainFbContext_(fbContext), glFbContext_(new FrameBufferContext(*fbContext->getV4D(), "OpenGL" + std::to_string(idx), fbContext)) {
#ifdef __EMSCRIPTEN__
run_sync_on_main<19>([&,this](){
mainFbContext_->initWebGLCopy(fbCtx()->getIndex());
});
#endif
}
void GLContext::execute(std::function<void()> fn) {
run_sync_on_main<15>([this, fn](){
#ifndef __EMSCRIPTEN__
if(!fbCtx()->hasParent()) {
UMat tmp;
mainFbContext_->copyTo(tmp);
fbCtx()->copyFrom(tmp);
}
#endif
{
FrameBufferContext::GLScope glScope(fbCtx(), GL_FRAMEBUFFER);
GL_CHECK(glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT));
#ifdef __EMSCRIPTEN__
//Preserve the clear color state though it is a bit costly. We don't want to interfere.
GLfloat cColor[4];
GL_CHECK(glGetFloatv(GL_COLOR_CLEAR_VALUE, cColor));
GL_CHECK(glClearColor(0,0,0,0));
GL_CHECK(glClear(GL_COLOR_BUFFER_BIT));
GL_CHECK(glClearColor(cColor[0], cColor[1], cColor[2], cColor[3]));
#endif
fn();
}
if(!fbCtx()->hasParent()) {
#ifdef __EMSCRIPTEN__
mainFbContext_->doWebGLCopy(fbCtx());
#else
UMat tmp;
fbCtx()->copyTo(tmp);
mainFbContext_->copyFrom(tmp);
#endif
}
});
if(!fbCtx()->hasParent()) {
UMat tmp;
mainFbContext_->copyTo(tmp);
fbCtx()->copyFrom(tmp);
}
{
FrameBufferContext::GLScope glScope(fbCtx(), GL_FRAMEBUFFER);
GL_CHECK(glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT));
fn();
}
if(!fbCtx()->hasParent()) {
UMat tmp;
fbCtx()->copyTo(tmp);
mainFbContext_->copyFrom(tmp);
}
}
const int32_t& GLContext::getIndex() const {

@ -10,26 +10,24 @@ namespace v4d {
namespace detail {
ImGuiContextImpl::ImGuiContextImpl(cv::Ptr<FrameBufferContext> fbContext) :
mainFbContext_(fbContext) {
run_sync_on_main<27>([&,this](){
FrameBufferContext::GLScope glScope(mainFbContext_, GL_FRAMEBUFFER);
IMGUI_CHECKVERSION();
context_ = ImGui::CreateContext();
ImGui::SetCurrentContext(context_);
FrameBufferContext::GLScope glScope(mainFbContext_, GL_FRAMEBUFFER);
IMGUI_CHECKVERSION();
context_ = ImGui::CreateContext();
ImGui::SetCurrentContext(context_);
ImGuiIO& io = ImGui::GetIO();
(void)io;
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad;
ImGui::StyleColorsDark();
ImGuiIO& io = ImGui::GetIO();
(void)io;
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad;
ImGui::StyleColorsDark();
ImGui_ImplGlfw_InitForOpenGL(mainFbContext_->getGLFWWindow(), false);
ImGui_ImplGlfw_SetCallbacksChainForAllWindows(true);
#if !defined(OPENCV_V4D_USE_ES3) && !defined(__EMSCRIPTEN__)
ImGui_ImplOpenGL3_Init("#version 330");
ImGui_ImplGlfw_InitForOpenGL(mainFbContext_->getGLFWWindow(), false);
ImGui_ImplGlfw_SetCallbacksChainForAllWindows(true);
#if !defined(OPENCV_V4D_USE_ES3)
ImGui_ImplOpenGL3_Init("#version 330");
#else
ImGui_ImplOpenGL3_Init("#version 300 es");
ImGui_ImplOpenGL3_Init("#version 300 es");
#endif
});
}
void ImGuiContextImpl::build(std::function<void(ImGuiContext*)> fn) {
@ -42,57 +40,52 @@ void ImGuiContextImpl::makeCurrent() {
}
void ImGuiContextImpl::render(bool showFPS) {
{
mainFbContext_->makeCurrent();
ImGui::SetCurrentContext(context_);
mainFbContext_->makeCurrent();
ImGui::SetCurrentContext(context_);
GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, 0));
#if !defined(OPENCV_V4D_USE_ES3) && !defined(EMSCRIPTEN)
GL_CHECK(glDrawBuffer(GL_BACK));
GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, 0));
#if !defined(OPENCV_V4D_USE_ES3)
GL_CHECK(glDrawBuffer(GL_BACK));
#endif
GL_CHECK(
glViewport(0, 0, mainFbContext_->getWindowSize().width,
mainFbContext_->getWindowSize().height));
ImGui_ImplOpenGL3_NewFrame();
ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame();
if (showFPS) {
static bool open_ptr[1] = { true };
static ImGuiWindowFlags window_flags = 0;
ImGui_ImplOpenGL3_NewFrame();
ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame();
if (showFPS) {
static bool open_ptr[1] = { true };
static ImGuiWindowFlags window_flags = 0;
// window_flags |= ImGuiWindowFlags_NoBackground;
window_flags |= ImGuiWindowFlags_NoBringToFrontOnFocus;
window_flags |= ImGuiWindowFlags_NoMove;
window_flags |= ImGuiWindowFlags_NoScrollWithMouse;
window_flags |= ImGuiWindowFlags_AlwaysAutoResize;
window_flags |= ImGuiWindowFlags_NoSavedSettings;
window_flags |= ImGuiWindowFlags_NoFocusOnAppearing;
window_flags |= ImGuiWindowFlags_NoNav;
window_flags |= ImGuiWindowFlags_NoDecoration;
window_flags |= ImGuiWindowFlags_NoInputs;
static ImVec2 pos(0, 0);
ImGui::SetNextWindowPos(pos, ImGuiCond_Once);
ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(0.0f, 0.0f, 0.0f, 0.5f));
ImGui::Begin("Display", open_ptr, window_flags);
ImGui::Text("%.3f ms/frame (%.1f FPS)", (1000.0f / Global::fps()) , Global::fps());
ImGui::End();
ImGui::PopStyleColor(1);
std::stringstream ss;
TimeTracker::getInstance()->print(ss);
std::string line;
ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(0.0f, 0.0f, 0.0f, 0.5f));
ImGui::Begin("Time Tracking");
while(getline(ss, line)) {
ImGui::Text("%s", line.c_str());
}
ImGui::End();
ImGui::PopStyleColor(1);
}
if (renderCallback_)
renderCallback_(context_);
ImGui::Render();
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
mainFbContext_->makeNoneCurrent();
}
window_flags |= ImGuiWindowFlags_NoBringToFrontOnFocus;
window_flags |= ImGuiWindowFlags_NoMove;
window_flags |= ImGuiWindowFlags_NoScrollWithMouse;
window_flags |= ImGuiWindowFlags_AlwaysAutoResize;
window_flags |= ImGuiWindowFlags_NoSavedSettings;
window_flags |= ImGuiWindowFlags_NoFocusOnAppearing;
window_flags |= ImGuiWindowFlags_NoNav;
window_flags |= ImGuiWindowFlags_NoDecoration;
window_flags |= ImGuiWindowFlags_NoInputs;
static ImVec2 pos(0, 0);
ImGui::SetNextWindowPos(pos, ImGuiCond_Once);
ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(0.0f, 0.0f, 0.0f, 0.5f));
ImGui::Begin("Display", open_ptr, window_flags);
ImGui::Text("%.3f ms/frame (%.1f FPS)", (1000.0f / Global::fps()) , Global::fps());
ImGui::End();
ImGui::PopStyleColor(1);
std::stringstream ss;
TimeTracker::getInstance()->print(ss);
std::string line;
ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(0.0f, 0.0f, 0.0f, 0.5f));
ImGui::Begin("Time Tracking");
while(getline(ss, line)) {
ImGui::Text("%s", line.c_str());
}
ImGui::End();
ImGui::PopStyleColor(1);
}
if (renderCallback_)
renderCallback_(context_);
ImGui::Render();
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
mainFbContext_->makeNoneCurrent();
}
}
}

@ -15,62 +15,39 @@ namespace detail {
NanoVGContext::NanoVGContext(cv::Ptr<FrameBufferContext> fbContext) :
mainFbContext_(fbContext), nvgFbContext_(new FrameBufferContext(*fbContext->getV4D(), "NanoVG", fbContext)), context_(
nullptr) {
run_sync_on_main<13>([this]() {
{
FrameBufferContext::GLScope glScope(fbCtx(), GL_FRAMEBUFFER);
#if defined(OPENCV_V4D_USE_ES3) || defined(EMSCRIPTEN)
context_ = nvgCreateGLES3(NVG_ANTIALIAS | NVG_STENCIL_STROKES);
#else
context_ = nvgCreateGL3(NVG_ANTIALIAS | NVG_STENCIL_STROKES);
#endif
if (!context_)
CV_Error(Error::StsError, "Could not initialize NanoVG!");
#ifdef __EMSCRIPTEN__
nvgCreateFont(context_, "icons", "assets/fonts/entypo.ttf");
nvgCreateFont(context_, "sans", "assets/fonts/Roboto-Regular.ttf");
nvgCreateFont(context_, "sans-bold", "/assets/fonts/Roboto-Bold.ttf");
FrameBufferContext::GLScope glScope(fbCtx(), GL_FRAMEBUFFER);
#if defined(OPENCV_V4D_USE_ES3)
context_ = nvgCreateGLES3(NVG_ANTIALIAS | NVG_STENCIL_STROKES);
#else
nvgCreateFont(context_, "icons", "modules/v4d/assets/fonts/entypo.ttf");
nvgCreateFont(context_, "sans", "modules/v4d/assets/fonts/Roboto-Regular.ttf");
nvgCreateFont(context_, "sans-bold", "modules/v4d/assets/fonts/Roboto-Bold.ttf");
#endif
#ifdef __EMSCRIPTEN__
mainFbContext_->initWebGLCopy(fbCtx()->getIndex());
context_ = nvgCreateGL3(NVG_ANTIALIAS | NVG_STENCIL_STROKES);
#endif
}
});
if (!context_)
CV_Error(Error::StsError, "Could not initialize NanoVG!");
nvgCreateFont(context_, "icons", "modules/v4d/assets/fonts/entypo.ttf");
nvgCreateFont(context_, "sans", "modules/v4d/assets/fonts/Roboto-Regular.ttf");
nvgCreateFont(context_, "sans-bold", "modules/v4d/assets/fonts/Roboto-Bold.ttf");
}
void NanoVGContext::execute(std::function<void()> fn) {
run_sync_on_main<14>([this, fn]() {
#ifndef __EMSCRIPTEN__
if (!fbCtx()->hasParent()) {
UMat tmp;
mainFbContext_->copyTo(tmp);
fbCtx()->copyFrom(tmp);
}
#endif
{
FrameBufferContext::GLScope glScope(fbCtx(), GL_FRAMEBUFFER);
glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
#ifdef __EMSCRIPTEN__
glClearColor(0,0,0,0);
glClear(GL_COLOR_BUFFER_BIT);
#endif
NanoVGContext::Scope nvgScope(*this);
cv::v4d::nvg::detail::NVG::initializeContext(context_);
fn();
}
if (!fbCtx()->hasParent()) {
#ifdef __EMSCRIPTEN__
mainFbContext_->doWebGLCopy(fbCtx());
#else
UMat tmp;
fbCtx()->copyTo(tmp);
mainFbContext_->copyFrom(tmp);
#endif
}
});
}

@ -16,22 +16,16 @@ SinkContext::SinkContext(cv::Ptr<FrameBufferContext> mainFbContext) : mainFbCont
}
void SinkContext::execute(std::function<void()> fn) {
run_sync_on_main<31>([this,fn](){
#ifndef __EMSCRIPTEN__
if (hasContext()) {
CLExecScope_t scope(getCLExecContext());
#endif
fn();
#ifndef __EMSCRIPTEN__
} else {
fn();
}
#endif
auto v4d = mainFbContext_->getV4D();
if(v4d->hasSink()) {
v4d->getSink()->operator ()(v4d->sourceCtx()->sequenceNumber(), sinkBuffer());
}
});
auto v4d = mainFbContext_->getV4D();
if(v4d->hasSink()) {
v4d->getSink()->operator ()(v4d->sourceCtx()->sequenceNumber(), sinkBuffer());
}
}
bool SinkContext::hasContext() {
@ -39,9 +33,7 @@ bool SinkContext::hasContext() {
}
void SinkContext::copyContext() {
#ifndef __EMSCRIPTEN__
context_ = CLExecContext_t::getCurrent();
#endif
}
CLExecContext_t SinkContext::getCLExecContext() {

@ -4,9 +4,7 @@
// Copyright Amir Hassan (kallaballa) <amir@viel-zu.org>
#include "../../include/opencv2/v4d/detail/sourcecontext.hpp"
#include "../../include/opencv2/v4d/v4d.hpp"
#include <opencv2/imgproc.hpp>
namespace cv {
@ -17,11 +15,8 @@ SourceContext::SourceContext(cv::Ptr<FrameBufferContext> mainFbContext) : mainFb
}
void SourceContext::execute(std::function<void()> fn) {
run_sync_on_main<30>([this,fn](){
#ifndef __EMSCRIPTEN__
if (hasContext()) {
CLExecScope_t scope(getCLExecContext());
#endif
if (mainFbContext_->getV4D()->hasSource()) {
auto src = mainFbContext_->getV4D()->getSource();
@ -30,11 +25,7 @@ void SourceContext::execute(std::function<void()> fn) {
currentSeqNr_ = p.first;
if(p.second.empty()) {
#ifndef __EMSCRIPTEN__
throw std::runtime_error("End of stream");
#else
p.second.create(mainFbContext_->size(), CV_8UC3);
#endif
}
resizePreserveAspectRatio(p.second, captureBufferRGB_, mainFbContext_->size());
@ -42,8 +33,6 @@ void SourceContext::execute(std::function<void()> fn) {
}
}
fn();
#ifndef __EMSCRIPTEN__
} else {
if (mainFbContext_->getV4D()->hasSource()) {
auto src = mainFbContext_->getV4D()->getSource();
@ -53,11 +42,7 @@ void SourceContext::execute(std::function<void()> fn) {
currentSeqNr_ = p.first;
if(p.second.empty()) {
#ifndef __EMSCRIPTEN__
throw std::runtime_error("End of stream");
#else
p.second.create(mainFbContext_->size(), CV_8UC3);
#endif
}
resizePreserveAspectRatio(p.second, captureBufferRGB_, mainFbContext_->size());
cv::cvtColor(captureBufferRGB_, sourceBuffer(), cv::COLOR_RGB2BGRA);
@ -65,8 +50,6 @@ void SourceContext::execute(std::function<void()> fn) {
}
fn();
}
#endif
});
}
uint64_t SourceContext::sequenceNumber() {
@ -78,9 +61,7 @@ bool SourceContext::hasContext() {
}
void SourceContext::copyContext() {
#ifndef __EMSCRIPTEN__
context_ = CLExecContext_t::getCurrent();
#endif
}
CLExecContext_t SourceContext::getCLExecContext() {

@ -5,24 +5,10 @@
#include <opencv2/imgcodecs.hpp>
#include <opencv2/videoio.hpp>
#include "opencv2/v4d/util.hpp"
#include <opencv2/core/ocl.hpp>
#include "../include/opencv2/v4d/detail/sourcecontext.hpp"
#include "opencv2/v4d/v4d.hpp"
#include "opencv2/v4d/nvg.hpp"
#include "opencv2/v4d/detail/framebuffercontext.hpp"
#ifdef __EMSCRIPTEN__
# include <emscripten.h>
# include <emscripten/bind.h>
# include <SDL/SDL.h>
# include <SDL/SDL_image.h>
# include <SDL/SDL_stdinc.h>
#else
# include <opencv2/core/ocl.hpp>
#endif
#include "../include/opencv2/v4d/v4d.hpp"
#include "../include/opencv2/v4d/util.hpp"
#include <csignal>
#include <unistd.h>
@ -83,45 +69,7 @@ cv::Scalar colorConvert(const cv::Scalar& src, cv::ColorConversionCodes code) {
return dst;
}
#ifdef __EMSCRIPTEN__
Mat read_embedded_image(const string &path) {
SDL_Surface *loadedSurface = IMG_Load(path.c_str());
Mat result;
if (loadedSurface == NULL) {
printf("Unable to load image %s! SDL_image Error: %s\n", path.c_str(),
IMG_GetError());
} else {
if (loadedSurface->w == 0 && loadedSurface->h == 0) {
std::cerr << "Empty image loaded" << std::endl;
SDL_FreeSurface(loadedSurface);
return Mat();
}
if(loadedSurface->format->BytesPerPixel == 1) {
result = Mat(loadedSurface->h, loadedSurface->w, CV_8UC1, (unsigned char*) loadedSurface->pixels, loadedSurface->pitch).clone();
cvtColor(result,result, COLOR_GRAY2BGR);
} else if(loadedSurface->format->BytesPerPixel == 3) {
result = Mat(loadedSurface->h, loadedSurface->w, CV_8UC3, (unsigned char*) loadedSurface->pixels, loadedSurface->pitch).clone();
if(loadedSurface->format->Rmask == 0x0000ff)
cvtColor(result,result, COLOR_RGB2BGR);
} else if(loadedSurface->format->BytesPerPixel == 4) {
result = Mat(loadedSurface->h, loadedSurface->w, CV_8UC4, (unsigned char*) loadedSurface->pixels, loadedSurface->pitch).clone();
if(loadedSurface->format->Rmask == 0x000000ff)
cvtColor(result,result, COLOR_RGBA2BGR);
else
cvtColor(result,result, COLOR_RGBA2RGB);
} else {
std::cerr << "Unsupported image depth" << std::endl;
SDL_FreeSurface(loadedSurface);
return Mat();
}
SDL_FreeSurface(loadedSurface);
}
return result;
}
#endif
void gl_check_error(const std::filesystem::path& file, unsigned int line, const char* expression) {
#ifndef NDEBUG
int errorCode = glGetError();
// cerr << "TRACE: " << file.filename() << " (" << line << ") : " << expression << " => code: " << errorCode << endl;
if (errorCode != 0) {
@ -130,11 +78,6 @@ void gl_check_error(const std::filesystem::path& file, unsigned int line, const
<< expression << "\nError code:\n " << errorCode;
CV_LOG_WARNING(nullptr, ss.str());
}
#else
CV_UNUSED(file);
CV_UNUSED(line);
CV_UNUSED(expression);
#endif
}
unsigned int initShader(const char* vShader, const char* fShader, const char* outputAttributeName) {
@ -167,7 +110,7 @@ unsigned int initShader(const char* vShader, const char* fShader, const char* ou
glAttachShader(program, shader);
}
#if !defined(__EMSCRIPTEN__) && !defined(OPENCV_V4D_USE_ES3)
#if !defined(OPENCV_V4D_USE_ES3)
/* Link output */
glBindFragDataLocation(program, 0, outputAttributeName);
#else
@ -211,7 +154,6 @@ std::string getGlInfo() {
std::string getClInfo() {
std::stringstream ss;
#ifndef __EMSCRIPTEN__
std::vector<cv::ocl::PlatformInfo> plt_info;
cv::ocl::getPlatfomsInfo(plt_info);
const cv::ocl::Device& defaultDevice = cv::ocl::Device::getDefault();
@ -234,12 +176,10 @@ std::string getClInfo() {
"true" : "false") << endl;
}
}
#endif
return ss.str();
}
bool isIntelVaSupported() {
#ifndef __EMSCRIPTEN__
try {
std::vector<cv::ocl::PlatformInfo> plt_info;
cv::ocl::getPlatfomsInfo(plt_info);
@ -255,12 +195,11 @@ bool isIntelVaSupported() {
} catch (...) {
cerr << "Intel VAAPI query failed" << endl;
}
#endif
return false;
}
bool isClGlSharingSupported() {
#ifndef __EMSCRIPTEN__
try {
if(!cv::ocl::useOpenCL())
return false;
@ -278,7 +217,7 @@ bool isClGlSharingSupported() {
} catch (...) {
cerr << "CL-GL sharing query failed with unknown error." << endl;
}
#endif
return false;
}
@ -319,7 +258,6 @@ void requestFinish() {
request_finish(0);
}
#ifndef __EMSCRIPTEN__
cv::Ptr<Sink> makeVaSink(cv::Ptr<V4D> window, const string& outputFilename, const int fourcc, const float fps,
const cv::Size& frameSize, const int vaDeviceIndex) {
cv::Ptr<cv::VideoWriter> writer = new cv::VideoWriter(outputFilename, cv::CAP_FFMPEG,
@ -392,9 +330,7 @@ static cv::Ptr<Source> makeAnyHWSource(const string& inputFilename) {
return !frame.empty();
}, fps);
}
#endif
#ifndef __EMSCRIPTEN__
cv::Ptr<Sink> makeWriterSink(cv::Ptr<V4D> window, const string& outputFilename, const float fps, const cv::Size& frameSize) {
int fourcc = 0;
//FIXME find a cleverer way to guess a decent codec
@ -455,111 +391,6 @@ cv::Ptr<Source> makeCaptureSource(cv::Ptr<V4D> window, const string& inputFilena
}, fps);
}
#else
using namespace emscripten;
class HTML5Capture {
private:
cv::Ptr<V4D> window_;
int width_;
int height_;
GLuint framebuffer = 0;
GLuint texture = 0;
public:
HTML5Capture(cv::Ptr<V4D> window, int width, int height) :
window_(window), width_(width), height_(height) {
EM_ASM({
globalThis.playing = false;
globalThis.timeupdate = false;
globalThis.v4dVideoElement = document.querySelector("#v4dVideoElement");
}, width, height);
}
bool captureGPU() {
FrameBufferContext::GLScope scope(window_->fbCtx());
int ret = EM_ASM_INT(
if(typeof Module.ctx !== 'undefined' && Module.ctx != null && globalThis.doCapture) {
globalThis.gl = Module.ctx;
globalThis.v4dMainFrameBuffer = globalThis.gl.getParameter(globalThis.gl.FRAMEBUFFER_BINDING);
globalThis.v4dMainTexture = globalThis.gl.getFramebufferAttachmentParameter(globalThis.gl.FRAMEBUFFER, globalThis.gl.COLOR_ATTACHMENT0, globalThis.gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME);
return 1;
} else {
return 0;
}
);
if(ret) {
if(framebuffer == 0) {
GL_CHECK(glGenFramebuffers(1, &framebuffer));
}
GL_CHECK(glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer));
if(texture == 0) {
GL_CHECK(glGenTextures(1, &texture));
}
GL_CHECK(glBindTexture(GL_TEXTURE_2D, texture));
EM_ASM(
const level = 0;
const internalFormat = globalThis.gl.RGBA;
const border = 0;
const srcFormat = globalThis.gl.RGBA;
const srcType = globalThis.gl.UNSIGNED_BYTE;
globalThis.gl.texImage2D(
globalThis.gl.TEXTURE_2D,
level,
internalFormat,
srcFormat,
srcType,
globalThis.v4dVideoElement
);
);
GL_CHECK(glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0));
cv::Size fbSz = window_->fbSize();
window_->fbCtx()->blitFrameBufferToFrameBuffer(cv::Rect(0, 0, width_, height_), cv::Size(fbSz.width, fbSz.height), window_->fbCtx()->getFramebufferID(), true, true);
return true;
}
return false;
}
};
cv::Ptr<HTML5Capture> capture = nullptr;
static thread_local int capture_width = 0;
static thread_local int capture_height = 0;
extern "C" {
EMSCRIPTEN_KEEPALIVE
void v4dInitCapture(int width, int height) {
capture_width = width;
capture_height = height;
}
}
cv::Ptr<Source> makeCaptureSource(cv::Ptr<V4D> window) {
using namespace std;
return new Source([window](cv::UMat& frame) {
if(capture_width > 0 && capture_height > 0) {
try {
run_sync_on_main<17>([&]() {
if(capture == nullptr)
capture = new HTML5Capture(window, capture_width, capture_height);
capture->captureGPU();
});
} catch(std::exception& ex) {
cerr << ex.what() << endl;
}
}
return true;
}, 0);
}
#endif
void resizePreserveAspectRatio(const cv::UMat& src, cv::UMat& output, const cv::Size& dstSize, const cv::Scalar& bgcolor) {
cv::UMat tmp;
double hf = double(dstSize.height) / src.size().height;

@ -37,15 +37,10 @@ cv::Ptr<V4D> V4D::make(const V4D& other, const string& title) {
V4D::V4D(const cv::Size& size, const cv::Size& fbsize, const string& title, AllocateFlags flags, bool offscreen, bool debug, int samples) :
initialSize_(size), debug_(debug), viewport_(0, 0, size.width, size.height), stretching_(true), samples_(samples) {
#ifdef __EMSCRIPTEN__
printf(""); //makes sure we have FS as a dependency
#endif
self_ = cv::Ptr<V4D>(this);
mainFbContext_ = new detail::FrameBufferContext(*this, fbsize.empty() ? size : fbsize, offscreen, title, 3,
2, samples, debug, nullptr, nullptr, true);
#ifndef __EMSCRIPTEN__
CLExecScope_t scope(mainFbContext_->getCLExecContext());
#endif
if(flags & NANOVG)
nvgContext_ = new detail::NanoVGContext(mainFbContext_);
sourceContext_ = new detail::SourceContext(mainFbContext_);
@ -61,17 +56,12 @@ V4D::V4D(const cv::Size& size, const cv::Size& fbsize, const string& title, Allo
V4D::V4D(const V4D& other, const string& title) :
initialSize_(other.initialSize_), debug_(other.debug_), viewport_(0, 0, other.fbSize().width, other.fbSize().height), stretching_(other.stretching_), samples_(other.samples_) {
#ifdef __EMSCRIPTEN__
printf(""); //makes sure we have FS as a dependency
#endif
workerIdx_ = Global::workers_running()++;
self_ = cv::Ptr<V4D>(this);
mainFbContext_ = new detail::FrameBufferContext(*this, other.fbSize(), !other.debug_, title, 3,
2, other.samples_, other.debug_, other.fbCtx()->rootWindow_, other.fbCtx(), true);
#ifndef __EMSCRIPTEN__
CLExecScope_t scope(mainFbContext_->getCLExecContext());
#endif
//FIXME we don't always need the nvg context
nvgContext_ = new detail::NanoVGContext(mainFbContext_);
sourceContext_ = new detail::SourceContext(mainFbContext_);
@ -230,7 +220,7 @@ void V4D::feed(cv::UMat& in) {
}
cv::UMat V4D::fetch() {
cv::UMat frame;
static thread_local cv::UMat frame;
fb([](const cv::UMat& fb, cv::UMat& f) {
fb.copyTo(f);
}, frame);
@ -355,33 +345,21 @@ void V4D::swapContextBuffers() {
FrameBufferContext::GLScope glScope(glCtx(-1)->fbCtx(), GL_READ_FRAMEBUFFER);
glCtx(-1)->fbCtx()->blitFrameBufferToFrameBuffer(viewport(), glCtx(-1)->fbCtx()->getWindowSize(), 0, isStretching());
// GL_CHECK(glFinish());
#ifndef __EMSCRIPTEN__
glfwSwapBuffers(glCtx(-1)->fbCtx()->getGLFWWindow());
#else
emscripten_webgl_commit_frame();
#endif
}
for(size_t i = 0; i < numGlCtx(); ++i) {
FrameBufferContext::GLScope glScope(glCtx(i)->fbCtx(), GL_READ_FRAMEBUFFER);
glCtx(i)->fbCtx()->blitFrameBufferToFrameBuffer(viewport(), glCtx(i)->fbCtx()->getWindowSize(), 0, isStretching());
// GL_CHECK(glFinish());
#ifndef __EMSCRIPTEN__
glfwSwapBuffers(glCtx(i)->fbCtx()->getGLFWWindow());
#else
emscripten_webgl_commit_frame();
#endif
}
if(hasNvgCtx()) {
FrameBufferContext::GLScope glScope(nvgCtx()->fbCtx(), GL_READ_FRAMEBUFFER);
nvgCtx()->fbCtx()->blitFrameBufferToFrameBuffer(viewport(), nvgCtx()->fbCtx()->getWindowSize(), 0, isStretching());
// GL_CHECK(glFinish());
#ifndef __EMSCRIPTEN__
glfwSwapBuffers(nvgCtx()->fbCtx()->getGLFWWindow());
#else
emscripten_webgl_commit_frame();
#endif
}
}
@ -390,65 +368,41 @@ bool V4D::display() {
if(!Global::is_main())
++Global::frame_cnt();
run_sync_on_main<6>([&, this]() {
#ifndef __EMSCRIPTEN__
if(debug_) {
swapContextBuffers();
}
#else
if(debug_) {
swapContextBuffers();
#endif
#ifndef __EMSCRIPTEN__
if (Global::is_main()) {
#else
if (true) {
#endif
auto start = Global::start_time();
auto now = get_epoch_nanos();
double diff_seconds = (now - start) / 1000000000.0;
Global::fps() = (Global::frame_cnt()) / diff_seconds;
if(getPrintFPS())
cerr << "\rFPS:" << Global::fps() << endl;
{
FrameBufferContext::GLScope glScope(fbCtx(), GL_READ_FRAMEBUFFER);
fbCtx()->blitFrameBufferToFrameBuffer(viewport(), fbCtx()->getWindowSize(), 0, isStretching());
}
if(hasImguiCtx())
imguiCtx()->render(getShowFPS());
} else {
// fbCtx()->makeCurrent();
fbCtx()->copyToRootWindow();
}
// fbCtx()->makeCurrent();
#ifndef __EMSCRIPTEN__
glfwSwapBuffers(fbCtx()->getGLFWWindow());
#else
emscripten_webgl_commit_frame();
#endif
glfwPollEvents();
result = !glfwWindowShouldClose(getGLFWWindow());
// {
// FrameBufferContext::GLScope glScope(fbCtx(), GL_DRAW_FRAMEBUFFER);
// GL_CHECK(glViewport(0, 0, fbCtx()->size().width, fbCtx()->size().height));
// GL_CHECK(glClearColor(0,0,0,0));
// GL_CHECK(glClear(GL_COLOR_BUFFER_BIT));
// }
//#ifndef __EMSCRIPTEN__
// {
// GL_CHECK(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0));
// GL_CHECK(glViewport(0, 0, size().width, size().height));
// GL_CHECK(glClearColor(0,0,0,255));
// GL_CHECK(glClear(GL_COLOR_BUFFER_BIT));
// }
}
if (Global::is_main()) {
auto start = Global::start_time();
auto now = get_epoch_nanos();
double diff_seconds = (now - start) / 1000000000.0;
Global::fps() = (Global::frame_cnt()) / diff_seconds;
if(getPrintFPS())
cerr << "\rFPS:" << Global::fps() << endl;
{
FrameBufferContext::GLScope glScope(fbCtx(), GL_READ_FRAMEBUFFER);
fbCtx()->blitFrameBufferToFrameBuffer(viewport(), fbCtx()->getWindowSize(), 0, isStretching());
}
if(hasImguiCtx())
imguiCtx()->render(getShowFPS());
} else {
fbCtx()->copyToRootWindow();
}
glfwSwapBuffers(fbCtx()->getGLFWWindow());
glfwPollEvents();
result = !glfwWindowShouldClose(getGLFWWindow());
//FIXME doesn't have any effect
// GL_CHECK(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0));
//#if !defined(OPENCV_V4D_USE_ES3)
// GL_CHECK(glDrawBuffer(GL_BACK));
//#endif
});
// GL_CHECK(glViewport(0, 0, size().width, size().height));
// GL_CHECK(glClearColor(1,0,0,255));
// GL_CHECK(glClear(GL_COLOR_BUFFER_BIT));
if (frameCnt_ == (std::numeric_limits<uint64_t>().max() - 1))
frameCnt_ = 0;
@ -475,16 +429,10 @@ GLFWwindow* V4D::getGLFWWindow() const {
}
void V4D::printSystemInfo() {
run_sync_on_main<8>([this](){
cerr << "OpenGL: " << getGlInfo() << endl;
cerr << "OpenCL Platforms: " << getClInfo() << endl;
});
cerr << "OpenGL: " << getGlInfo() << endl;
cerr << "OpenCL Platforms: " << getClInfo() << endl;
}
//void V4D::makeCurrent() {
// fbCtx()->makeCurrent();
//}
cv::Ptr<V4D> V4D::self() {
return self_;
}

Loading…
Cancel
Save