ported multi-context rendering to the new api

pull/3471/head
kallaballa 2 years ago
parent 050977370d
commit 66966406a3
  1. 5
      modules/v4d/include/opencv2/v4d/detail/glcontext.hpp
  2. 6
      modules/v4d/include/opencv2/v4d/util.hpp
  3. 60
      modules/v4d/include/opencv2/v4d/v4d.hpp
  4. 320
      modules/v4d/samples/many_cubes-demo.cpp
  5. 4
      modules/v4d/samples/video-demo.cpp
  6. 7
      modules/v4d/src/detail/glcontext.cpp
  7. 5
      modules/v4d/src/v4d.cpp

@ -20,6 +20,7 @@ namespace detail {
* Used to setup an OpengLG context * Used to setup an OpengLG context
*/ */
class CV_EXPORTS GLContext : public V4DContext { class CV_EXPORTS GLContext : public V4DContext {
const int32_t idx_;
cv::Ptr<FrameBufferContext> mainFbContext_; cv::Ptr<FrameBufferContext> mainFbContext_;
cv::Ptr<FrameBufferContext> glFbContext_; cv::Ptr<FrameBufferContext> glFbContext_;
public: public:
@ -27,7 +28,7 @@ public:
* Creates a OpenGL Context * Creates a OpenGL Context
* @param fbContext The framebuffer context * @param fbContext The framebuffer context
*/ */
GLContext(cv::Ptr<FrameBufferContext> fbContext); GLContext(const int32_t& idx, cv::Ptr<FrameBufferContext> fbContext);
virtual ~GLContext() {}; virtual ~GLContext() {};
/*! /*!
* Execute function object fn inside a gl context. * Execute function object fn inside a gl context.
@ -36,7 +37,7 @@ public:
* and performs drawing using opengl * and performs drawing using opengl
*/ */
virtual void execute(std::function<void()> fn) override; virtual void execute(std::function<void()> fn) override;
const int32_t& getIndex() const;
cv::Ptr<FrameBufferContext> fbCtx(); cv::Ptr<FrameBufferContext> fbCtx();
}; };
} }

@ -217,10 +217,8 @@ struct Lambda {
template<typename T> template<typename T>
static const void* fn(const void* new_fn = nullptr) { static const void* fn(const void* new_fn = nullptr) {
thread_local const void* fn; CV_Assert(new_fn);
if (new_fn != nullptr) return new_fn;
fn = new_fn;
return fn;
} }
}; };

@ -82,22 +82,15 @@ namespace detail {
template <typename T> using static_not = std::integral_constant<bool, !T::value>; template <typename T> using static_not = std::integral_constant<bool, !T::value>;
//https://stackoverflow.com/questions/19961873/test-if-a-lambda-is-stateless#:~:text=As%20per%20the%20Standard%2C%20if,lambda%20is%20stateless%20or%20not. template<typename T, typename ... Args>
template <typename T, typename U> struct is_function
struct helper : helper<T, decltype(&U::operator())>
{};
template <typename T, typename C, typename R, typename... A>
struct helper<T, R(C::*)(A...) const>
{ {
static const bool value = std::is_convertible<T, std::function<R(A...)>>::value || std::is_convertible<T, R(*)(A...)>::value; static const bool value = std::is_constructible<T,std::function<void(Args...)>>::value;
}; };
template<typename T> //https://stackoverflow.com/a/34873353/1884837
struct is_stateless template<class T>
{ struct is_stateless_lambda : std::integral_constant<bool, sizeof(T) == sizeof(std::true_type)>{};
static const bool value = helper<T,T>::value;
};
template<typename T> std::string int_to_hex( T i ) template<typename T> std::string int_to_hex( T i )
{ {
@ -108,13 +101,10 @@ template<typename T> std::string int_to_hex( T i )
return stream.str(); return stream.str();
} }
//template<typename Tfn> std::string func_hex(Tfn& fn) {
// return int_to_hex((size_t) &fn);
//}
template<typename Tlamba> std::string lambda_ptr_hex(Tlamba&& l) { template<typename Tlamba> std::string lambda_ptr_hex(Tlamba&& l) {
return int_to_hex((size_t)Lambda::ptr(l)); return int_to_hex((size_t)Lambda::ptr(l));
} }
} }
using namespace cv::v4d::detail; using namespace cv::v4d::detail;
@ -342,8 +332,9 @@ public:
} }
template <typename Tfn, typename ... Args> template <typename Tfn, typename ... Args>
void gl(Tfn fn, Args&& ... args) { typename std::enable_if<std::is_invocable_v<Tfn>, void>::type
CV_Assert(detail::is_stateless<std::remove_cv_t<std::remove_reference_t<decltype(fn)>>>::value); gl(Tfn fn, Args&& ... args) {
CV_Assert(detail::is_stateless_lambda<std::remove_cv_t<std::remove_reference_t<decltype(fn)>>>::value);
const string id = make_id("gl", fn, -1); const string id = make_id("gl", fn, -1);
TimeTracker::getInstance()->execute(id, [this, fn, id, &args...](){ TimeTracker::getInstance()->execute(id, [this, fn, id, &args...](){
emit_access<std::true_type, cv::UMat, Args...>(id, true, &fbCtx()->fb()); emit_access<std::true_type, cv::UMat, Args...>(id, true, &fbCtx()->fb());
@ -355,21 +346,22 @@ public:
} }
template <typename Tfn, typename ... Args> template <typename Tfn, typename ... Args>
void gl(const size_t& idx, Tfn fn, Args&& ... args) { void gl(int32_t idx, Tfn fn, Args&& ... args) {
CV_Assert(detail::is_stateless<std::remove_cv_t<std::remove_reference_t<decltype(fn)>>>::value); CV_Assert(detail::is_stateless_lambda<std::remove_cv_t<std::remove_reference_t<decltype(fn)>>>::value);
const string id = make_id("gl", fn, idx); const string id = make_id("gl", fn, idx);
TimeTracker::getInstance()->execute(id, [this, fn, idx, id, &args...](){ TimeTracker::getInstance()->execute(id, [this, fn, idx, id, &args...](){
emit_access<std::true_type, cv::UMat, Args...>(id, true, &fbCtx()->fb()); emit_access<std::true_type, cv::UMat, Args...>(id, true, &fbCtx()->fb());
(emit_access<std::true_type, std::remove_reference_t<Args>, Args...>(id, std::is_const_v<std::remove_reference_t<Args>>, &args),...); (emit_access<std::true_type, std::remove_reference_t<Args>, Args...>(id, std::is_const_v<std::remove_reference_t<Args>>, &args),...);
emit_access<std::true_type, cv::UMat, Args...>(id, false, &fbCtx()->fb()); emit_access<std::true_type, cv::UMat, Args...>(id, false, &fbCtx()->fb());
std::function functor(fn); std::function<void((const int32_t&,Args...))> functor(fn);
add_transaction(glCtx(idx), id, std::forward<decltype(functor)>(fn), std::forward<Args>(args)...); add_transaction<decltype(functor),const int32_t&>(fbCtx(),id, std::forward<decltype(functor)>(functor), glCtx(idx)->getIndex(), std::forward<Args>(args)...);
}); });
} }
template <typename Tfn> template <typename Tfn>
void branch(Tfn fn) { void branch(Tfn fn) {
CV_Assert(detail::is_stateless<std::remove_cv_t<std::remove_reference_t<decltype(fn)>>>::value); CV_Assert(detail::is_stateless_lambda<std::remove_cv_t<std::remove_reference_t<decltype(fn)>>>::value);
const string id = make_id("branch", fn); const string id = make_id("branch", fn);
TimeTracker::getInstance()->execute(id, [this, fn, id](){ TimeTracker::getInstance()->execute(id, [this, fn, id](){
@ -381,7 +373,7 @@ public:
template <typename Tfn, typename ... Args> template <typename Tfn, typename ... Args>
void branch(Tfn fn, Args&& ... args) { void branch(Tfn fn, Args&& ... args) {
CV_Assert(detail::is_stateless<std::remove_cv_t<std::remove_reference_t<decltype(fn)>>>::value); CV_Assert(detail::is_stateless_lambda<std::remove_cv_t<std::remove_reference_t<decltype(fn)>>>::value);
const string id = make_id("branch", fn); const string id = make_id("branch", fn);
TimeTracker::getInstance()->execute(id, [this, fn, id, &args...](){ TimeTracker::getInstance()->execute(id, [this, fn, id, &args...](){
@ -393,7 +385,7 @@ public:
template <typename Tfn> template <typename Tfn>
void endbranch(Tfn fn) { void endbranch(Tfn fn) {
CV_Assert(detail::is_stateless<std::remove_cv_t<std::remove_reference_t<decltype(fn)>>>::value); CV_Assert(detail::is_stateless_lambda<std::remove_cv_t<std::remove_reference_t<decltype(fn)>>>::value);
const string id = make_id("endbranch", fn); const string id = make_id("endbranch", fn);
TimeTracker::getInstance()->execute(id, [this, fn, id] { TimeTracker::getInstance()->execute(id, [this, fn, id] {
@ -405,7 +397,7 @@ public:
template <typename Tfn, typename ... Args> template <typename Tfn, typename ... Args>
void endbranch(Tfn fn, Args&& ... args) { void endbranch(Tfn fn, Args&& ... args) {
CV_Assert(detail::is_stateless<std::remove_cv_t<std::remove_reference_t<decltype(fn)>>>::value); CV_Assert(detail::is_stateless_lambda<std::remove_cv_t<std::remove_reference_t<decltype(fn)>>>::value);
const string id = make_id("endbranch", fn); const string id = make_id("endbranch", fn);
TimeTracker::getInstance()->execute(id, [this, fn, id, &args...](){ TimeTracker::getInstance()->execute(id, [this, fn, id, &args...](){
@ -417,7 +409,7 @@ public:
template <typename Tfn, typename ... Args> template <typename Tfn, typename ... Args>
void fb(Tfn fn, Args&& ... args) { void fb(Tfn fn, Args&& ... args) {
CV_Assert(detail::is_stateless<std::remove_cv_t<std::remove_reference_t<decltype(fn)>>>::value); CV_Assert(detail::is_stateless_lambda<std::remove_cv_t<std::remove_reference_t<decltype(fn)>>>::value);
const string id = make_id("fb", fn); const string id = make_id("fb", fn);
TimeTracker::getInstance()->execute(id, [this, fn, id, &args...]{ TimeTracker::getInstance()->execute(id, [this, fn, id, &args...]{
using Tfb = std::add_lvalue_reference_t<typename std::tuple_element<0, typename function_traits<Tfn>::argument_types>::type>; using Tfb = std::add_lvalue_reference_t<typename std::tuple_element<0, typename function_traits<Tfn>::argument_types>::type>;
@ -455,7 +447,7 @@ public:
template <typename Tfn, typename ... Args> template <typename Tfn, typename ... Args>
void capture(Tfn fn, Args&& ... args) { void capture(Tfn fn, Args&& ... args) {
CV_Assert(detail::is_stateless<std::remove_cv_t<std::remove_reference_t<decltype(fn)>>>::value); CV_Assert(detail::is_stateless_lambda<std::remove_cv_t<std::remove_reference_t<decltype(fn)>>>::value);
const string id = make_id("capture", fn); const string id = make_id("capture", fn);
TimeTracker::getInstance()->execute(id, [this, fn, id, &args...]{ TimeTracker::getInstance()->execute(id, [this, fn, id, &args...]{
using Tfb = std::add_lvalue_reference_t<typename std::tuple_element<0, typename function_traits<Tfn>::argument_types>::type>; using Tfb = std::add_lvalue_reference_t<typename std::tuple_element<0, typename function_traits<Tfn>::argument_types>::type>;
@ -488,7 +480,7 @@ public:
template <typename Tfn, typename ... Args> template <typename Tfn, typename ... Args>
void write(Tfn fn, Args&& ... args) { void write(Tfn fn, Args&& ... args) {
CV_Assert(detail::is_stateless<std::remove_cv_t<std::remove_reference_t<decltype(fn)>>>::value); CV_Assert(detail::is_stateless_lambda<std::remove_cv_t<std::remove_reference_t<decltype(fn)>>>::value);
const string id = make_id("write", fn); const string id = make_id("write", fn);
TimeTracker::getInstance()->execute(id, [this, fn, id, &args...]{ TimeTracker::getInstance()->execute(id, [this, fn, id, &args...]{
using Tfb = std::add_lvalue_reference_t<typename std::tuple_element<0, typename function_traits<Tfn>::argument_types>::type>; using Tfb = std::add_lvalue_reference_t<typename std::tuple_element<0, typename function_traits<Tfn>::argument_types>::type>;
@ -504,7 +496,7 @@ public:
template <typename Tfn, typename ... Args> template <typename Tfn, typename ... Args>
void nvg(Tfn fn, Args&&... args) { void nvg(Tfn fn, Args&&... args) {
CV_Assert(detail::is_stateless<std::remove_cv_t<std::remove_reference_t<decltype(fn)>>>::value); CV_Assert(detail::is_stateless_lambda<std::remove_cv_t<std::remove_reference_t<decltype(fn)>>>::value);
const string id = make_id("nvg", fn); const string id = make_id("nvg", fn);
TimeTracker::getInstance()->execute(id, [this, fn, id, &args...](){ TimeTracker::getInstance()->execute(id, [this, fn, id, &args...](){
emit_access<std::true_type, cv::UMat, Args...>(id, true, &fbCtx()->fb()); emit_access<std::true_type, cv::UMat, Args...>(id, true, &fbCtx()->fb());
@ -517,7 +509,7 @@ public:
template <typename Tfn, typename ... Args> template <typename Tfn, typename ... Args>
void single(Tfn fn, Args&&... args) { void single(Tfn fn, Args&&... args) {
CV_Assert(detail::is_stateless<std::remove_cv_t<std::remove_reference_t<decltype(fn)>>>::value); CV_Assert(detail::is_stateless_lambda<std::remove_cv_t<std::remove_reference_t<decltype(fn)>>>::value);
const string id = make_id("single", fn); const string id = make_id("single", fn);
TimeTracker::getInstance()->execute(id, [this, fn, id, &args...](){ TimeTracker::getInstance()->execute(id, [this, fn, id, &args...](){
(emit_access<std::true_type, std::remove_reference_t<Args>, Args...>(id, std::is_const_v<std::remove_reference_t<Args>>, &args),...); (emit_access<std::true_type, std::remove_reference_t<Args>, Args...>(id, std::is_const_v<std::remove_reference_t<Args>>, &args),...);
@ -528,7 +520,7 @@ public:
template <typename Tfn, typename ... Args> template <typename Tfn, typename ... Args>
void parallel(Tfn fn, Args&&... args) { void parallel(Tfn fn, Args&&... args) {
CV_Assert(detail::is_stateless<std::remove_cv_t<std::remove_reference_t<decltype(fn)>>>::value); CV_Assert(detail::is_stateless_lambda<std::remove_cv_t<std::remove_reference_t<decltype(fn)>>>::value);
const string id = make_id("parallel", fn); const string id = make_id("parallel", fn);
TimeTracker::getInstance()->execute(id, [this, fn, id, &args...](){ TimeTracker::getInstance()->execute(id, [this, fn, id, &args...](){
(emit_access<std::true_type, std::remove_reference_t<Args>, Args...>(id, std::is_const_v<std::remove_reference_t<Args>>, &args),...); (emit_access<std::true_type, std::remove_reference_t<Args>, Args...>(id, std::is_const_v<std::remove_reference_t<Args>>, &args),...);
@ -539,7 +531,7 @@ public:
template<typename Tfn, typename ... Args> template<typename Tfn, typename ... Args>
void imgui(Tfn fn, Args&& ... args) { void imgui(Tfn fn, Args&& ... args) {
CV_Assert(detail::is_stateless<std::remove_cv_t<std::remove_reference_t<decltype(fn)>>>::value); CV_Assert(detail::is_stateless_lambda<std::remove_cv_t<std::remove_reference_t<decltype(fn)>>>::value);
auto s = self(); auto s = self();
imguiCtx()->build([s, fn, &args...](ImGuiContext* ctx) { imguiCtx()->build([s, fn, &args...](ImGuiContext* ctx) {
fn(s, ctx, args...); fn(s, ctx, args...);

@ -7,7 +7,6 @@
//adapted from https://gitlab.com/wikibooks-opengl/modern-tutorials/-/blob/master/tut05_cube/cube.cpp //adapted from https://gitlab.com/wikibooks-opengl/modern-tutorials/-/blob/master/tut05_cube/cube.cpp
/* Demo Parameters */ /* Demo Parameters */
#ifndef __EMSCRIPTEN__ #ifndef __EMSCRIPTEN__
constexpr size_t NUMBER_OF_CUBES = 10; constexpr size_t NUMBER_OF_CUBES = 10;
constexpr long unsigned int WIDTH = 1280; constexpr long unsigned int WIDTH = 1280;
@ -23,7 +22,7 @@ constexpr double FPS = 60;
constexpr const char* OUTPUT_FILENAME = "many_cubes-demo.mkv"; constexpr const char* OUTPUT_FILENAME = "many_cubes-demo.mkv";
#endif #endif
const unsigned long DIAG = hypot(double(WIDTH), double(HEIGHT)); const unsigned long DIAG = hypot(double(WIDTH), double(HEIGHT));
const int glow_kernel_size = std::max(int(DIAG / 138 % 2 == 0 ? DIAG / 138 + 1 : DIAG / 138), 1); const int GLOW_KERNEL_SIZE = std::max(int(DIAG / 138 % 2 == 0 ? DIAG / 138 + 1 : DIAG / 138), 1);
using std::cerr; using std::cerr;
using std::endl; using std::endl;
@ -65,173 +64,178 @@ const unsigned short triangle_indices[] = {
// Top // Top
5, 1, 0, 0, 4, 5 5, 1, 0, 0, 4, 5
}; };
//Simple transform & pass-through shaders
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)
const string shaderVersion = "330";
#else
const string shaderVersion = "300 es";
#endif
const string vert = using namespace cv::v4d;
" #version " + shaderVersion class ManyCubesDemoPlan : public Plan {
+ R"( struct Cache {
precision lowp float; cv::UMat down_;
layout(location = 0) in vec3 pos; cv::UMat up_;
layout(location = 1) in vec3 vertex_color; cv::UMat blur_;
cv::UMat dst16_;
uniform mat4 transform; } cache_;
cv::UMat frame_;
out vec3 color; GLuint vao[NUMBER_OF_CUBES];
void main() { GLuint shaderProgram[NUMBER_OF_CUBES];
gl_Position = transform * vec4(pos, 1.0); GLuint uniformTransform[NUMBER_OF_CUBES];
color = vertex_color; cv::Size sz_;
} //Simple transform & pass-through shaders
)"; static GLuint load_shader() {
//Shader versions "330" and "300 es" are very similar.
const string frag = //If you are careful you can write the same code for both versions.
" #version " + shaderVersion #if !defined(__EMSCRIPTEN__) && !defined(OPENCV_V4D_USE_ES3)
+ R"( const string shaderVersion = "330";
precision lowp float; #else
in vec3 color; const string shaderVersion = "300 es";
#endif
out vec4 frag_color;
const string vert =
void main() { " #version " + shaderVersion
frag_color = vec4(color, 1.0); + R"(
} precision lowp float;
)"; layout(location = 0) in vec3 pos;
layout(location = 1) in vec3 vertex_color;
//Initialize the shaders and returns the program
return cv::v4d::initShader(vert.c_str(), frag.c_str(), "fragColor"); uniform mat4 transform;
}
out vec3 color;
void main() {
gl_Position = transform * vec4(pos, 1.0);
color = vertex_color;
}
)";
const string frag =
" #version " + shaderVersion
+ R"(
precision lowp float;
in vec3 color;
out vec4 frag_color;
void main() {
frag_color = vec4(color, 1.0);
}
)";
//Initialize the shaders and returns the program
return cv::v4d::initShader(vert.c_str(), frag.c_str(), "fragColor");
}
//Initializes objects, buffers, shaders and uniforms //Initializes objects, buffers, shaders and uniforms
static void init_scene(const cv::Size& sz, GLuint& vao, GLuint& shaderProgram, GLuint& uniformTransform) { static void init_scene(const cv::Size& sz, GLuint& vao, GLuint& shaderProgram, GLuint& uniformTransform) {
glEnable (GL_DEPTH_TEST); glEnable (GL_DEPTH_TEST);
glGenVertexArrays(1, &vao); glGenVertexArrays(1, &vao);
glBindVertexArray(vao); glBindVertexArray(vao);
unsigned int triangles_ebo; unsigned int triangles_ebo;
glGenBuffers(1, &triangles_ebo); glGenBuffers(1, &triangles_ebo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, triangles_ebo); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, triangles_ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof triangle_indices, triangle_indices, glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof triangle_indices, triangle_indices,
GL_STATIC_DRAW); GL_STATIC_DRAW);
unsigned int verticies_vbo; unsigned int verticies_vbo;
glGenBuffers(1, &verticies_vbo); glGenBuffers(1, &verticies_vbo);
glBindBuffer(GL_ARRAY_BUFFER, verticies_vbo); glBindBuffer(GL_ARRAY_BUFFER, verticies_vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof vertices, vertices, GL_STATIC_DRAW); glBufferData(GL_ARRAY_BUFFER, sizeof vertices, vertices, GL_STATIC_DRAW);
glVertexAttribPointer(vertices_index, 3, GL_FLOAT, GL_FALSE, 0, NULL); glVertexAttribPointer(vertices_index, 3, GL_FLOAT, GL_FALSE, 0, NULL);
glEnableVertexAttribArray(vertices_index); glEnableVertexAttribArray(vertices_index);
unsigned int colors_vbo; unsigned int colors_vbo;
glGenBuffers(1, &colors_vbo); glGenBuffers(1, &colors_vbo);
glBindBuffer(GL_ARRAY_BUFFER, colors_vbo); glBindBuffer(GL_ARRAY_BUFFER, colors_vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof vertex_colors, vertex_colors, GL_STATIC_DRAW); glBufferData(GL_ARRAY_BUFFER, sizeof vertex_colors, vertex_colors, GL_STATIC_DRAW);
glVertexAttribPointer(colors_index, 3, GL_FLOAT, GL_FALSE, 0, NULL); glVertexAttribPointer(colors_index, 3, GL_FLOAT, GL_FALSE, 0, NULL);
glEnableVertexAttribArray(colors_index); glEnableVertexAttribArray(colors_index);
glBindVertexArray(0); glBindVertexArray(0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ARRAY_BUFFER, 0);
shaderProgram = load_shader(); shaderProgram = load_shader();
uniformTransform = glGetUniformLocation(shaderProgram, "transform"); uniformTransform = glGetUniformLocation(shaderProgram, "transform");
glViewport(0,0, sz.width, sz.height); glViewport(0,0, sz.width, sz.height);
} }
//Renders a rotating rainbow-colored cube on a blueish background //Renders a rotating rainbow-colored cube on a blueish background
static void render_scene(const double& x, const double& y, const double& angleMod, GLuint& vao, GLuint& shaderProgram, GLuint& uniformTransform) { static void render_scene(const double& x, const double& y, const double& angleMod, GLuint& vao, GLuint& shaderProgram, GLuint& uniformTransform) {
//Use the prepared shader program //Use the prepared shader program
glUseProgram(shaderProgram); glUseProgram(shaderProgram);
//Scale and rotate the cube depending on the current time. //Scale and rotate the cube depending on the current time.
float angle = fmod(double(cv::getTickCount()) / double(cv::getTickFrequency()) + angleMod, 2 * M_PI); float angle = fmod(double(cv::getTickCount()) / double(cv::getTickFrequency()) + angleMod, 2 * M_PI);
double scale = 0.25; double scale = 0.25;
cv::Matx44f scaleMat( cv::Matx44f scaleMat(
scale, 0.0, 0.0, 0.0, scale, 0.0, 0.0, 0.0,
0.0, scale, 0.0, 0.0, 0.0, scale, 0.0, 0.0,
0.0, 0.0, scale, 0.0, 0.0, 0.0, scale, 0.0,
0.0, 0.0, 0.0, 1.0); 0.0, 0.0, 0.0, 1.0);
cv::Matx44f rotXMat( cv::Matx44f rotXMat(
1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0,
0.0, cos(angle), -sin(angle), 0.0, 0.0, cos(angle), -sin(angle), 0.0,
0.0, sin(angle), cos(angle), 0.0, 0.0, sin(angle), cos(angle), 0.0,
0.0, 0.0, 0.0, 1.0); 0.0, 0.0, 0.0, 1.0);
cv::Matx44f rotYMat( cv::Matx44f rotYMat(
cos(angle), 0.0, sin(angle), 0.0, cos(angle), 0.0, sin(angle), 0.0,
0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0,
-sin(angle), 0.0,cos(angle), 0.0, -sin(angle), 0.0,cos(angle), 0.0,
0.0, 0.0, 0.0, 1.0); 0.0, 0.0, 0.0, 1.0);
cv::Matx44f rotZMat( cv::Matx44f rotZMat(
cos(angle), -sin(angle), 0.0, 0.0, cos(angle), -sin(angle), 0.0, 0.0,
sin(angle), cos(angle), 0.0, 0.0, sin(angle), cos(angle), 0.0, 0.0,
0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0,
0.0, 0.0, 0.0, 1.0); 0.0, 0.0, 0.0, 1.0);
cv::Matx44f translateMat( cv::Matx44f translateMat(
1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0,
x, y, 0.0, 1.0); x, y, 0.0, 1.0);
//calculate the transform //calculate the transform
cv::Matx44f transform = scaleMat * rotXMat * rotYMat * rotZMat * translateMat; cv::Matx44f transform = scaleMat * rotXMat * rotYMat * rotZMat * translateMat;
//set the corresponding uniform //set the corresponding uniform
glUniformMatrix4fv(uniformTransform, 1, GL_FALSE, transform.val); glUniformMatrix4fv(uniformTransform, 1, GL_FALSE, transform.val);
//Bind our vertex array //Bind our vertex array
glBindVertexArray(vao); glBindVertexArray(vao);
//Draw //Draw
glDrawElements(GL_TRIANGLES, triangles * 3, GL_UNSIGNED_SHORT, NULL); glDrawElements(GL_TRIANGLES, triangles * 3, GL_UNSIGNED_SHORT, NULL);
} }
#ifndef __EMSCRIPTEN__ #ifndef __EMSCRIPTEN__
//applies a glow effect to an image //applies a glow effect to an image
static void glow_effect(const cv::UMat& src, cv::UMat& dst, const int ksize) { static void glow_effect(const cv::UMat& src, cv::UMat& dst, const int ksize, Cache& cache) {
thread_local cv::UMat resize; cv::bitwise_not(src, dst);
thread_local cv::UMat blur;
thread_local cv::UMat dst16; //Resize for some extra performance
cv::resize(dst, cache.down_, cv::Size(), 0.5, 0.5);
cv::bitwise_not(src, dst); //Cheap blur
cv::boxFilter(cache.down_, cache.blur_, -1, cv::Size(ksize, ksize), cv::Point(-1, -1), true,
//Resize for some extra performance cv::BORDER_REPLICATE);
cv::resize(dst, resize, cv::Size(), 0.5, 0.5); //Back to original size
//Cheap blur cv::resize(cache.blur_, cache.up_, src.size());
cv::boxFilter(resize, resize, -1, cv::Size(ksize, ksize), cv::Point(-1, -1), true,
cv::BORDER_REPLICATE); //Multiply the src image with a blurred version of itself
//Back to original size cv::multiply(dst, cache.up_, cache.dst16_, 1, CV_16U);
cv::resize(resize, blur, src.size()); //Normalize and convert back to CV_8U
cv::divide(cache.dst16_, cv::Scalar::all(255.0), dst, 1, CV_8U);
//Multiply the src image with a blurred version of itself
cv::multiply(dst, blur, dst16, 1, CV_16U); cv::bitwise_not(dst, dst);
//Normalize and convert back to CV_8U }
cv::divide(dst16, cv::Scalar::all(255.0), dst, 1, CV_8U);
cv::bitwise_not(dst, dst);
}
#endif #endif
using namespace cv::v4d;
class ManyCubesDemoPlan : public Plan {
cv::UMat frame_;
GLuint vao[NUMBER_OF_CUBES];
GLuint shaderProgram[NUMBER_OF_CUBES];
GLuint uniformTransform[NUMBER_OF_CUBES];
public: public:
void setup(cv::Ptr<V4D> window) { void setup(cv::Ptr<V4D> window) {
sz_ = window->fbSize();
for(size_t i = 0; i < NUMBER_OF_CUBES; ++i) { for(size_t i = 0; i < NUMBER_OF_CUBES; ++i) {
window->gl(i, [](const cv::Size& sz, GLuint& v, GLuint& sp, GLuint& ut){ window->gl(i, [](const size_t& ctxIdx, cv::Size& sz, GLuint& v, GLuint& sp, GLuint& ut){
init_scene(sz, v, sp, ut); CV_UNUSED(ctxIdx);
}, window->fbSize(), vao[i], shaderProgram[i], uniformTransform[i]); init_scene(sz, v, sp, ut);
}, sz_, vao[i], shaderProgram[i], uniformTransform[i]);
} }
} }
void infer(cv::Ptr<V4D> window) { void infer(cv::Ptr<V4D> window) {
@ -243,20 +247,20 @@ public:
//Render using multiple OpenGL contexts //Render using multiple OpenGL contexts
for(size_t i = 0; i < NUMBER_OF_CUBES; ++i) { for(size_t i = 0; i < NUMBER_OF_CUBES; ++i) {
window->gl(i, [i](GLuint& v, GLuint& sp, GLuint& ut){ window->gl(i, [](const int32_t& ctxIdx, GLuint& v, GLuint& sp, GLuint& ut){
double pos = (((double(i) / NUMBER_OF_CUBES) * 2.0) - 1) + (1.0 / NUMBER_OF_CUBES); double pos = (((double(ctxIdx) / NUMBER_OF_CUBES) * 2.0) - 1) + (1.0 / NUMBER_OF_CUBES);
double angle = sin((double(i) / NUMBER_OF_CUBES) * 2 * M_PI); double angle = sin((double(ctxIdx) / NUMBER_OF_CUBES) * 2 * M_PI);
render_scene(pos, pos, angle, v, sp, ut); render_scene(pos, pos, angle, v, sp, ut);
}, vao[i], shaderProgram[i], uniformTransform[i]); }, vao[i], shaderProgram[i], uniformTransform[i]);
} }
//Aquire the frame buffer for use by OpenCV //Aquire the frame buffer for use by OpenCV
window->fb([](cv::UMat& framebuffer, cv::UMat& f) { window->fb([](cv::UMat& framebuffer, cv::UMat& f, Cache& cache) {
#ifndef __EMSCRIPTEN__ #ifndef __EMSCRIPTEN__
glow_effect(framebuffer, framebuffer, glow_kernel_size); glow_effect(framebuffer, framebuffer, GLOW_KERNEL_SIZE, cache);
#endif #endif
framebuffer.copyTo(f); framebuffer.copyTo(f);
}, frame_); }, frame_, cache_);
window->write([](cv::UMat& outputFrame, const cv::UMat& f){ window->write([](cv::UMat& outputFrame, const cv::UMat& f){
f.copyTo(outputFrame); f.copyTo(outputFrame);

@ -24,7 +24,7 @@ constexpr long unsigned int HEIGHT = 960;
#endif #endif
constexpr bool OFFSCREEN = false; constexpr bool OFFSCREEN = false;
const unsigned long DIAG = hypot(double(WIDTH), double(HEIGHT)); const unsigned long DIAG = hypot(double(WIDTH), double(HEIGHT));
const int glow_kernel_size = std::max(int(DIAG / 138 % 2 == 0 ? DIAG / 138 + 1 : DIAG / 138), 1); const int GLOW_KERNEL_SIZE = std::max(int(DIAG / 138 % 2 == 0 ? DIAG / 138 + 1 : DIAG / 138), 1);
#ifndef __EMSCRIPTEN__ #ifndef __EMSCRIPTEN__
constexpr double FPS = 60; constexpr double FPS = 60;
constexpr const char* OUTPUT_FILENAME = "video-demo.mkv"; constexpr const char* OUTPUT_FILENAME = "video-demo.mkv";
@ -205,7 +205,7 @@ public:
#ifndef __EMSCRIPTEN__ #ifndef __EMSCRIPTEN__
window->fb([](cv::UMat &framebuffer) { window->fb([](cv::UMat &framebuffer) {
glow_effect(framebuffer, framebuffer, glow_kernel_size); glow_effect(framebuffer, framebuffer, GLOW_KERNEL_SIZE);
}); });
#endif #endif

@ -9,8 +9,8 @@
namespace cv { namespace cv {
namespace v4d { namespace v4d {
namespace detail { namespace detail {
GLContext::GLContext(cv::Ptr<FrameBufferContext> fbContext) : GLContext::GLContext(const int32_t& idx, cv::Ptr<FrameBufferContext> fbContext) :
mainFbContext_(fbContext), glFbContext_(new FrameBufferContext(*fbContext->getV4D(), "OpenGL", *fbContext)) { idx_(idx), mainFbContext_(fbContext), glFbContext_(new FrameBufferContext(*fbContext->getV4D(), "OpenGL", *fbContext)) {
#ifdef __EMSCRIPTEN__ #ifdef __EMSCRIPTEN__
run_sync_on_main<19>([&,this](){ run_sync_on_main<19>([&,this](){
mainFbContext_->initWebGLCopy(fbCtx()->getIndex()); mainFbContext_->initWebGLCopy(fbCtx()->getIndex());
@ -52,6 +52,9 @@ void GLContext::execute(std::function<void()> fn) {
}); });
} }
const int32_t& GLContext::getIndex() const {
return idx_;
}
cv::Ptr<FrameBufferContext> GLContext::fbCtx() { cv::Ptr<FrameBufferContext> GLContext::fbCtx() {
return glFbContext_; return glFbContext_;
} }

@ -46,6 +46,9 @@ V4D::V4D(const cv::Size& size, const cv::Size& fbsize, const string& title, Allo
parallelContext_ = new detail::ParallelContext(); parallelContext_ = new detail::ParallelContext();
if(flags & IMGUI) if(flags & IMGUI)
imguiContext_ = new detail::ImGuiContextImpl(mainFbContext_); imguiContext_ = new detail::ImGuiContextImpl(mainFbContext_);
//preallocate the primary gl context
glCtx(-1);
} }
V4D::~V4D() { V4D::~V4D() {
@ -113,7 +116,7 @@ cv::Ptr<GLContext> V4D::glCtx(int32_t idx) {
if(it != glContexts_.end()) if(it != glContexts_.end())
return (*it).second; return (*it).second;
else { else {
cv::Ptr<GLContext> ctx = new GLContext(mainFbContext_); cv::Ptr<GLContext> ctx = new GLContext(idx, mainFbContext_);
glContexts_.insert({idx, ctx}); glContexts_.insert({idx, ctx});
return ctx; return ctx;
} }

Loading…
Cancel
Save