diff --git a/modules/v4d/include/opencv2/v4d/detail/glcontext.hpp b/modules/v4d/include/opencv2/v4d/detail/glcontext.hpp index d7f95aa91..e31b734a9 100644 --- a/modules/v4d/include/opencv2/v4d/detail/glcontext.hpp +++ b/modules/v4d/include/opencv2/v4d/detail/glcontext.hpp @@ -20,6 +20,7 @@ namespace detail { * Used to setup an OpengLG context */ class CV_EXPORTS GLContext : public V4DContext { + const int32_t idx_; cv::Ptr mainFbContext_; cv::Ptr glFbContext_; public: @@ -27,7 +28,7 @@ public: * Creates a OpenGL Context * @param fbContext The framebuffer context */ - GLContext(cv::Ptr fbContext); + GLContext(const int32_t& idx, cv::Ptr fbContext); virtual ~GLContext() {}; /*! * Execute function object fn inside a gl context. @@ -36,7 +37,7 @@ public: * and performs drawing using opengl */ virtual void execute(std::function fn) override; - + const int32_t& getIndex() const; cv::Ptr fbCtx(); }; } diff --git a/modules/v4d/include/opencv2/v4d/util.hpp b/modules/v4d/include/opencv2/v4d/util.hpp index c0c662eb4..17171bf85 100644 --- a/modules/v4d/include/opencv2/v4d/util.hpp +++ b/modules/v4d/include/opencv2/v4d/util.hpp @@ -217,10 +217,8 @@ struct Lambda { template static const void* fn(const void* new_fn = nullptr) { - thread_local const void* fn; - if (new_fn != nullptr) - fn = new_fn; - return fn; + CV_Assert(new_fn); + return new_fn; } }; diff --git a/modules/v4d/include/opencv2/v4d/v4d.hpp b/modules/v4d/include/opencv2/v4d/v4d.hpp index ac6278920..877b30631 100644 --- a/modules/v4d/include/opencv2/v4d/v4d.hpp +++ b/modules/v4d/include/opencv2/v4d/v4d.hpp @@ -82,22 +82,15 @@ namespace detail { template using static_not = std::integral_constant; -//https://stackoverflow.com/questions/19961873/test-if-a-lambda-is-stateless#:~:text=As%20per%20the%20Standard%2C%20if,lambda%20is%20stateless%20or%20not. -template -struct helper : helper -{}; - -template -struct helper +template +struct is_function { - static const bool value = std::is_convertible>::value || std::is_convertible::value; + static const bool value = std::is_constructible>::value; }; -template -struct is_stateless -{ - static const bool value = helper::value; -}; +//https://stackoverflow.com/a/34873353/1884837 +template +struct is_stateless_lambda : std::integral_constant{}; template std::string int_to_hex( T i ) { @@ -108,13 +101,10 @@ template std::string int_to_hex( T i ) return stream.str(); } -//template std::string func_hex(Tfn& fn) { -// return int_to_hex((size_t) &fn); -//} - template std::string lambda_ptr_hex(Tlamba&& l) { return int_to_hex((size_t)Lambda::ptr(l)); } + } using namespace cv::v4d::detail; @@ -342,8 +332,9 @@ public: } template - void gl(Tfn fn, Args&& ... args) { - CV_Assert(detail::is_stateless>>::value); + typename std::enable_if, void>::type + gl(Tfn fn, Args&& ... args) { + CV_Assert(detail::is_stateless_lambda>>::value); const string id = make_id("gl", fn, -1); TimeTracker::getInstance()->execute(id, [this, fn, id, &args...](){ emit_access(id, true, &fbCtx()->fb()); @@ -355,21 +346,22 @@ public: } template - void gl(const size_t& idx, Tfn fn, Args&& ... args) { - CV_Assert(detail::is_stateless>>::value); + void gl(int32_t idx, Tfn fn, Args&& ... args) { + CV_Assert(detail::is_stateless_lambda>>::value); + const string id = make_id("gl", fn, idx); TimeTracker::getInstance()->execute(id, [this, fn, idx, id, &args...](){ emit_access(id, true, &fbCtx()->fb()); (emit_access, Args...>(id, std::is_const_v>, &args),...); emit_access(id, false, &fbCtx()->fb()); - std::function functor(fn); - add_transaction(glCtx(idx), id, std::forward(fn), std::forward(args)...); + std::function functor(fn); + add_transaction(fbCtx(),id, std::forward(functor), glCtx(idx)->getIndex(), std::forward(args)...); }); } template void branch(Tfn fn) { - CV_Assert(detail::is_stateless>>::value); + CV_Assert(detail::is_stateless_lambda>>::value); const string id = make_id("branch", fn); TimeTracker::getInstance()->execute(id, [this, fn, id](){ @@ -381,7 +373,7 @@ public: template void branch(Tfn fn, Args&& ... args) { - CV_Assert(detail::is_stateless>>::value); + CV_Assert(detail::is_stateless_lambda>>::value); const string id = make_id("branch", fn); TimeTracker::getInstance()->execute(id, [this, fn, id, &args...](){ @@ -393,7 +385,7 @@ public: template void endbranch(Tfn fn) { - CV_Assert(detail::is_stateless>>::value); + CV_Assert(detail::is_stateless_lambda>>::value); const string id = make_id("endbranch", fn); TimeTracker::getInstance()->execute(id, [this, fn, id] { @@ -405,7 +397,7 @@ public: template void endbranch(Tfn fn, Args&& ... args) { - CV_Assert(detail::is_stateless>>::value); + CV_Assert(detail::is_stateless_lambda>>::value); const string id = make_id("endbranch", fn); TimeTracker::getInstance()->execute(id, [this, fn, id, &args...](){ @@ -417,7 +409,7 @@ public: template void fb(Tfn fn, Args&& ... args) { - CV_Assert(detail::is_stateless>>::value); + CV_Assert(detail::is_stateless_lambda>>::value); const string id = make_id("fb", fn); TimeTracker::getInstance()->execute(id, [this, fn, id, &args...]{ using Tfb = std::add_lvalue_reference_t::argument_types>::type>; @@ -455,7 +447,7 @@ public: template void capture(Tfn fn, Args&& ... args) { - CV_Assert(detail::is_stateless>>::value); + CV_Assert(detail::is_stateless_lambda>>::value); const string id = make_id("capture", fn); TimeTracker::getInstance()->execute(id, [this, fn, id, &args...]{ using Tfb = std::add_lvalue_reference_t::argument_types>::type>; @@ -488,7 +480,7 @@ public: template void write(Tfn fn, Args&& ... args) { - CV_Assert(detail::is_stateless>>::value); + CV_Assert(detail::is_stateless_lambda>>::value); const string id = make_id("write", fn); TimeTracker::getInstance()->execute(id, [this, fn, id, &args...]{ using Tfb = std::add_lvalue_reference_t::argument_types>::type>; @@ -504,7 +496,7 @@ public: template void nvg(Tfn fn, Args&&... args) { - CV_Assert(detail::is_stateless>>::value); + CV_Assert(detail::is_stateless_lambda>>::value); const string id = make_id("nvg", fn); TimeTracker::getInstance()->execute(id, [this, fn, id, &args...](){ emit_access(id, true, &fbCtx()->fb()); @@ -517,7 +509,7 @@ public: template void single(Tfn fn, Args&&... args) { - CV_Assert(detail::is_stateless>>::value); + CV_Assert(detail::is_stateless_lambda>>::value); const string id = make_id("single", fn); TimeTracker::getInstance()->execute(id, [this, fn, id, &args...](){ (emit_access, Args...>(id, std::is_const_v>, &args),...); @@ -528,7 +520,7 @@ public: template void parallel(Tfn fn, Args&&... args) { - CV_Assert(detail::is_stateless>>::value); + CV_Assert(detail::is_stateless_lambda>>::value); const string id = make_id("parallel", fn); TimeTracker::getInstance()->execute(id, [this, fn, id, &args...](){ (emit_access, Args...>(id, std::is_const_v>, &args),...); @@ -539,7 +531,7 @@ public: template void imgui(Tfn fn, Args&& ... args) { - CV_Assert(detail::is_stateless>>::value); + CV_Assert(detail::is_stateless_lambda>>::value); auto s = self(); imguiCtx()->build([s, fn, &args...](ImGuiContext* ctx) { fn(s, ctx, args...); diff --git a/modules/v4d/samples/many_cubes-demo.cpp b/modules/v4d/samples/many_cubes-demo.cpp index e322f9b16..adf7ce3e3 100644 --- a/modules/v4d/samples/many_cubes-demo.cpp +++ b/modules/v4d/samples/many_cubes-demo.cpp @@ -7,7 +7,6 @@ //adapted from https://gitlab.com/wikibooks-opengl/modern-tutorials/-/blob/master/tut05_cube/cube.cpp /* Demo Parameters */ - #ifndef __EMSCRIPTEN__ constexpr size_t NUMBER_OF_CUBES = 10; constexpr long unsigned int WIDTH = 1280; @@ -23,7 +22,7 @@ constexpr double FPS = 60; constexpr const char* OUTPUT_FILENAME = "many_cubes-demo.mkv"; #endif 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::endl; @@ -65,173 +64,178 @@ const unsigned short triangle_indices[] = { // Top 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 = - " #version " + shaderVersion - + R"( - precision lowp float; - layout(location = 0) in vec3 pos; - layout(location = 1) in vec3 vertex_color; - - 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"); -} +using namespace cv::v4d; +class ManyCubesDemoPlan : public Plan { + struct Cache { + cv::UMat down_; + cv::UMat up_; + cv::UMat blur_; + cv::UMat dst16_; + } cache_; + cv::UMat frame_; + GLuint vao[NUMBER_OF_CUBES]; + GLuint shaderProgram[NUMBER_OF_CUBES]; + GLuint uniformTransform[NUMBER_OF_CUBES]; + cv::Size sz_; + //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 = + " #version " + shaderVersion + + R"( + precision lowp float; + layout(location = 0) in vec3 pos; + layout(location = 1) in vec3 vertex_color; + + 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 -static void init_scene(const cv::Size& sz, GLuint& vao, GLuint& shaderProgram, GLuint& uniformTransform) { - glEnable (GL_DEPTH_TEST); + //Initializes objects, buffers, shaders and uniforms + static void init_scene(const cv::Size& sz, GLuint& vao, GLuint& shaderProgram, GLuint& uniformTransform) { + glEnable (GL_DEPTH_TEST); - glGenVertexArrays(1, &vao); - glBindVertexArray(vao); + glGenVertexArrays(1, &vao); + glBindVertexArray(vao); - unsigned int triangles_ebo; - glGenBuffers(1, &triangles_ebo); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, triangles_ebo); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof triangle_indices, triangle_indices, - GL_STATIC_DRAW); + unsigned int triangles_ebo; + glGenBuffers(1, &triangles_ebo); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, triangles_ebo); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof triangle_indices, triangle_indices, + GL_STATIC_DRAW); - unsigned int verticies_vbo; - glGenBuffers(1, &verticies_vbo); - glBindBuffer(GL_ARRAY_BUFFER, verticies_vbo); - glBufferData(GL_ARRAY_BUFFER, sizeof vertices, vertices, GL_STATIC_DRAW); + unsigned int verticies_vbo; + glGenBuffers(1, &verticies_vbo); + glBindBuffer(GL_ARRAY_BUFFER, verticies_vbo); + glBufferData(GL_ARRAY_BUFFER, sizeof vertices, vertices, GL_STATIC_DRAW); - glVertexAttribPointer(vertices_index, 3, GL_FLOAT, GL_FALSE, 0, NULL); - glEnableVertexAttribArray(vertices_index); + glVertexAttribPointer(vertices_index, 3, GL_FLOAT, GL_FALSE, 0, NULL); + glEnableVertexAttribArray(vertices_index); - unsigned int colors_vbo; - glGenBuffers(1, &colors_vbo); - glBindBuffer(GL_ARRAY_BUFFER, colors_vbo); - glBufferData(GL_ARRAY_BUFFER, sizeof vertex_colors, vertex_colors, GL_STATIC_DRAW); + unsigned int colors_vbo; + glGenBuffers(1, &colors_vbo); + glBindBuffer(GL_ARRAY_BUFFER, colors_vbo); + glBufferData(GL_ARRAY_BUFFER, sizeof vertex_colors, vertex_colors, GL_STATIC_DRAW); - glVertexAttribPointer(colors_index, 3, GL_FLOAT, GL_FALSE, 0, NULL); - glEnableVertexAttribArray(colors_index); + glVertexAttribPointer(colors_index, 3, GL_FLOAT, GL_FALSE, 0, NULL); + glEnableVertexAttribArray(colors_index); - glBindVertexArray(0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindVertexArray(0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + glBindBuffer(GL_ARRAY_BUFFER, 0); - shaderProgram = load_shader(); - uniformTransform = glGetUniformLocation(shaderProgram, "transform"); - glViewport(0,0, sz.width, sz.height); -} + shaderProgram = load_shader(); + uniformTransform = glGetUniformLocation(shaderProgram, "transform"); + glViewport(0,0, sz.width, sz.height); + } -//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) { - //Use the prepared shader program - glUseProgram(shaderProgram); - - //Scale and rotate the cube depending on the current time. - float angle = fmod(double(cv::getTickCount()) / double(cv::getTickFrequency()) + angleMod, 2 * M_PI); - double scale = 0.25; - cv::Matx44f scaleMat( - scale, 0.0, 0.0, 0.0, - 0.0, scale, 0.0, 0.0, - 0.0, 0.0, scale, 0.0, - 0.0, 0.0, 0.0, 1.0); - - cv::Matx44f rotXMat( - 1.0, 0.0, 0.0, 0.0, - 0.0, cos(angle), -sin(angle), 0.0, - 0.0, sin(angle), cos(angle), 0.0, - 0.0, 0.0, 0.0, 1.0); - - cv::Matx44f rotYMat( - cos(angle), 0.0, sin(angle), 0.0, - 0.0, 1.0, 0.0, 0.0, - -sin(angle), 0.0,cos(angle), 0.0, - 0.0, 0.0, 0.0, 1.0); - - cv::Matx44f rotZMat( - cos(angle), -sin(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, 0.0, 1.0); - - cv::Matx44f translateMat( - 1.0, 0.0, 0.0, 0.0, - 0.0, 1.0, 0.0, 0.0, - 0.0, 0.0, 1.0, 0.0, - x, y, 0.0, 1.0); - - //calculate the transform - cv::Matx44f transform = scaleMat * rotXMat * rotYMat * rotZMat * translateMat; - //set the corresponding uniform - glUniformMatrix4fv(uniformTransform, 1, GL_FALSE, transform.val); - //Bind our vertex array - glBindVertexArray(vao); - //Draw - glDrawElements(GL_TRIANGLES, triangles * 3, GL_UNSIGNED_SHORT, NULL); -} + //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) { + //Use the prepared shader program + glUseProgram(shaderProgram); + + //Scale and rotate the cube depending on the current time. + float angle = fmod(double(cv::getTickCount()) / double(cv::getTickFrequency()) + angleMod, 2 * M_PI); + double scale = 0.25; + cv::Matx44f scaleMat( + scale, 0.0, 0.0, 0.0, + 0.0, scale, 0.0, 0.0, + 0.0, 0.0, scale, 0.0, + 0.0, 0.0, 0.0, 1.0); + + cv::Matx44f rotXMat( + 1.0, 0.0, 0.0, 0.0, + 0.0, cos(angle), -sin(angle), 0.0, + 0.0, sin(angle), cos(angle), 0.0, + 0.0, 0.0, 0.0, 1.0); + + cv::Matx44f rotYMat( + cos(angle), 0.0, sin(angle), 0.0, + 0.0, 1.0, 0.0, 0.0, + -sin(angle), 0.0,cos(angle), 0.0, + 0.0, 0.0, 0.0, 1.0); + + cv::Matx44f rotZMat( + cos(angle), -sin(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, 0.0, 1.0); + + cv::Matx44f translateMat( + 1.0, 0.0, 0.0, 0.0, + 0.0, 1.0, 0.0, 0.0, + 0.0, 0.0, 1.0, 0.0, + x, y, 0.0, 1.0); + + //calculate the transform + cv::Matx44f transform = scaleMat * rotXMat * rotYMat * rotZMat * translateMat; + //set the corresponding uniform + glUniformMatrix4fv(uniformTransform, 1, GL_FALSE, transform.val); + //Bind our vertex array + glBindVertexArray(vao); + //Draw + 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) { - thread_local cv::UMat resize; - thread_local cv::UMat blur; - thread_local cv::UMat dst16; - - cv::bitwise_not(src, dst); - - //Resize for some extra performance - cv::resize(dst, resize, cv::Size(), 0.5, 0.5); - //Cheap blur - cv::boxFilter(resize, resize, -1, cv::Size(ksize, ksize), cv::Point(-1, -1), true, - cv::BORDER_REPLICATE); - //Back to original size - cv::resize(resize, blur, src.size()); - - //Multiply the src image with a blurred version of itself - cv::multiply(dst, blur, dst16, 1, CV_16U); - //Normalize and convert back to CV_8U - cv::divide(dst16, cv::Scalar::all(255.0), dst, 1, CV_8U); - - cv::bitwise_not(dst, dst); -} + //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); + + //Resize for some extra performance + cv::resize(dst, cache.down_, cv::Size(), 0.5, 0.5); + //Cheap blur + cv::boxFilter(cache.down_, cache.blur_, -1, cv::Size(ksize, ksize), cv::Point(-1, -1), true, + cv::BORDER_REPLICATE); + //Back to original size + cv::resize(cache.blur_, cache.up_, src.size()); + + //Multiply the src image with a blurred version of itself + cv::multiply(dst, cache.up_, cache.dst16_, 1, CV_16U); + //Normalize and convert back to CV_8U + cv::divide(cache.dst16_, cv::Scalar::all(255.0), dst, 1, CV_8U); + + cv::bitwise_not(dst, dst); + } #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: void setup(cv::Ptr window) { + sz_ = window->fbSize(); for(size_t i = 0; i < NUMBER_OF_CUBES; ++i) { - window->gl(i, [](const cv::Size& sz, GLuint& v, GLuint& sp, GLuint& ut){ - init_scene(sz, v, sp, ut); - }, window->fbSize(), vao[i], shaderProgram[i], uniformTransform[i]); + window->gl(i, [](const size_t& ctxIdx, cv::Size& sz, GLuint& v, GLuint& sp, GLuint& ut){ + CV_UNUSED(ctxIdx); + init_scene(sz, v, sp, ut); + }, sz_, vao[i], shaderProgram[i], uniformTransform[i]); } } void infer(cv::Ptr window) { @@ -243,20 +247,20 @@ public: //Render using multiple OpenGL contexts for(size_t i = 0; i < NUMBER_OF_CUBES; ++i) { - window->gl(i, [i](GLuint& v, GLuint& sp, GLuint& ut){ - double pos = (((double(i) / NUMBER_OF_CUBES) * 2.0) - 1) + (1.0 / NUMBER_OF_CUBES); - double angle = sin((double(i) / NUMBER_OF_CUBES) * 2 * M_PI); + window->gl(i, [](const int32_t& ctxIdx, GLuint& v, GLuint& sp, GLuint& ut){ + double pos = (((double(ctxIdx) / NUMBER_OF_CUBES) * 2.0) - 1) + (1.0 / NUMBER_OF_CUBES); + double angle = sin((double(ctxIdx) / NUMBER_OF_CUBES) * 2 * M_PI); render_scene(pos, pos, angle, v, sp, ut); }, vao[i], shaderProgram[i], uniformTransform[i]); } //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__ - glow_effect(framebuffer, framebuffer, glow_kernel_size); + glow_effect(framebuffer, framebuffer, GLOW_KERNEL_SIZE, cache); #endif framebuffer.copyTo(f); - }, frame_); + }, frame_, cache_); window->write([](cv::UMat& outputFrame, const cv::UMat& f){ f.copyTo(outputFrame); diff --git a/modules/v4d/samples/video-demo.cpp b/modules/v4d/samples/video-demo.cpp index 2ff8ab3d0..bd75fd523 100644 --- a/modules/v4d/samples/video-demo.cpp +++ b/modules/v4d/samples/video-demo.cpp @@ -24,7 +24,7 @@ constexpr long unsigned int HEIGHT = 960; #endif constexpr bool OFFSCREEN = false; 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__ constexpr double FPS = 60; constexpr const char* OUTPUT_FILENAME = "video-demo.mkv"; @@ -205,7 +205,7 @@ public: #ifndef __EMSCRIPTEN__ window->fb([](cv::UMat &framebuffer) { - glow_effect(framebuffer, framebuffer, glow_kernel_size); + glow_effect(framebuffer, framebuffer, GLOW_KERNEL_SIZE); }); #endif diff --git a/modules/v4d/src/detail/glcontext.cpp b/modules/v4d/src/detail/glcontext.cpp index e997f55f9..a43e76855 100644 --- a/modules/v4d/src/detail/glcontext.cpp +++ b/modules/v4d/src/detail/glcontext.cpp @@ -9,8 +9,8 @@ namespace cv { namespace v4d { namespace detail { -GLContext::GLContext(cv::Ptr fbContext) : - mainFbContext_(fbContext), glFbContext_(new FrameBufferContext(*fbContext->getV4D(), "OpenGL", *fbContext)) { +GLContext::GLContext(const int32_t& idx, cv::Ptr fbContext) : + idx_(idx), mainFbContext_(fbContext), glFbContext_(new FrameBufferContext(*fbContext->getV4D(), "OpenGL", *fbContext)) { #ifdef __EMSCRIPTEN__ run_sync_on_main<19>([&,this](){ mainFbContext_->initWebGLCopy(fbCtx()->getIndex()); @@ -52,6 +52,9 @@ void GLContext::execute(std::function fn) { }); } +const int32_t& GLContext::getIndex() const { + return idx_; +} cv::Ptr GLContext::fbCtx() { return glFbContext_; } diff --git a/modules/v4d/src/v4d.cpp b/modules/v4d/src/v4d.cpp index 9c886a968..4a6cce865 100644 --- a/modules/v4d/src/v4d.cpp +++ b/modules/v4d/src/v4d.cpp @@ -46,6 +46,9 @@ V4D::V4D(const cv::Size& size, const cv::Size& fbsize, const string& title, Allo parallelContext_ = new detail::ParallelContext(); if(flags & IMGUI) imguiContext_ = new detail::ImGuiContextImpl(mainFbContext_); + + //preallocate the primary gl context + glCtx(-1); } V4D::~V4D() { @@ -113,7 +116,7 @@ cv::Ptr V4D::glCtx(int32_t idx) { if(it != glContexts_.end()) return (*it).second; else { - cv::Ptr ctx = new GLContext(mainFbContext_); + cv::Ptr ctx = new GLContext(idx, mainFbContext_); glContexts_.insert({idx, ctx}); return ctx; }